summaryrefslogtreecommitdiffstats
path: root/src/target/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'src/target/firmware')
-rw-r--r--src/target/firmware/.gitignore9
-rw-r--r--src/target/firmware/COPYING339
-rw-r--r--src/target/firmware/Makefile108
-rw-r--r--src/target/firmware/Makefile.inc208
-rw-r--r--src/target/firmware/Makefile.mtk32
-rw-r--r--src/target/firmware/abb/twl3025.c368
-rw-r--r--src/target/firmware/apps/chainload/main.c54
-rw-r--r--src/target/firmware/apps/compal_dsp_dump/main.c85
-rw-r--r--src/target/firmware/apps/hello_world/main.c199
-rw-r--r--src/target/firmware/apps/layer1/main.c173
-rw-r--r--src/target/firmware/apps/loader/main.c445
-rw-r--r--src/target/firmware/apps/loader/protocol.h37
-rw-r--r--src/target/firmware/apps/loader_mtk/main.c366
-rw-r--r--src/target/firmware/apps/rssi/main.c1562
-rwxr-xr-xsrc/target/firmware/apps/simtest/main.c362
-rw-r--r--src/target/firmware/battery/compal_e88.c384
-rw-r--r--src/target/firmware/battery/dummy.c9
-rw-r--r--src/target/firmware/board/common/calypso_pwl.S21
-rw-r--r--src/target/firmware/board/common/calypso_uart.S92
-rw-r--r--src/target/firmware/board/compal/LINKAGE.txt12
-rw-r--r--src/target/firmware/board/compal/exceptions_redirect.S24
-rw-r--r--src/target/firmware/board/compal/exceptions_redirected.S20
-rw-r--r--src/target/firmware/board/compal/handlers.S79
-rw-r--r--src/target/firmware/board/compal/header.S11
-rw-r--r--src/target/firmware/board/compal/highram.lds121
-rw-r--r--src/target/firmware/board/compal/macros.S76
-rw-r--r--src/target/firmware/board/compal/ram.lds123
-rw-r--r--src/target/firmware/board/compal/rf_power.c62
-rw-r--r--src/target/firmware/board/compal/rffe_dualband.c102
-rw-r--r--src/target/firmware/board/compal/start.ram.S26
-rw-r--r--src/target/firmware/board/compal/start.rom.S32
-rw-r--r--src/target/firmware/board/compal_e86/init.c144
-rw-r--r--src/target/firmware/board/compal_e86/rffe_dualband_e86.c106
-rw-r--r--src/target/firmware/board/compal_e88/LINKAGE.txt33
-rw-r--r--src/target/firmware/board/compal_e88/MEMORY_MAP.txt21
-rw-r--r--src/target/firmware/board/compal_e88/flash.lds134
-rwxr-xr-xsrc/target/firmware/board/compal_e88/init.c140
-rw-r--r--src/target/firmware/board/compal_e88/loader.lds147
-rw-r--r--src/target/firmware/board/compal_e99/init.c142
-rw-r--r--src/target/firmware/board/gta0x/init.c133
-rw-r--r--src/target/firmware/board/gta0x/rf_power.c63
-rw-r--r--src/target/firmware/board/gta0x/rffe_gta0x_triband.c131
-rw-r--r--src/target/firmware/board/manifest.c7
-rw-r--r--src/target/firmware/board/mediatek/macros.S76
-rw-r--r--src/target/firmware/board/mediatek/ram.lds112
-rw-r--r--src/target/firmware/board/mediatek/start.ram.S26
-rw-r--r--src/target/firmware/board/mediatek/uart.c424
-rw-r--r--src/target/firmware/board/mt62xx/init.c139
-rw-r--r--src/target/firmware/board/pirelli_dpl10/init.c149
-rw-r--r--src/target/firmware/board/pirelli_dpl10/rf_power.c63
-rw-r--r--src/target/firmware/board/pirelli_dpl10/rffe_dpl10_triband.c136
-rw-r--r--src/target/firmware/board/se_j100/init.c141
-rw-r--r--src/target/firmware/calypso/Makefile4
-rw-r--r--src/target/firmware/calypso/arm.c26
-rw-r--r--src/target/firmware/calypso/backlight.c69
-rw-r--r--src/target/firmware/calypso/buzzer.c86
-rw-r--r--src/target/firmware/calypso/clock.c200
-rw-r--r--src/target/firmware/calypso/dma.c44
-rw-r--r--src/target/firmware/calypso/dsp.c693
-rw-r--r--src/target/firmware/calypso/dsp_bootcode.c9
-rw-r--r--src/target/firmware/calypso/dsp_dumpcode.c45
-rw-r--r--src/target/firmware/calypso/dsp_params.c94
-rw-r--r--src/target/firmware/calypso/du.c51
-rw-r--r--src/target/firmware/calypso/i2c.c123
-rw-r--r--src/target/firmware/calypso/irq.c266
-rw-r--r--src/target/firmware/calypso/keypad.c207
-rw-r--r--src/target/firmware/calypso/misc.c60
-rw-r--r--src/target/firmware/calypso/rtc.c78
-rw-r--r--src/target/firmware/calypso/sim.c741
-rw-r--r--src/target/firmware/calypso/spi.c141
-rw-r--r--src/target/firmware/calypso/timer.c156
-rw-r--r--src/target/firmware/calypso/tpu.c346
-rw-r--r--src/target/firmware/calypso/tsp.c121
-rw-r--r--src/target/firmware/calypso/uart.c440
-rw-r--r--src/target/firmware/calypso/uwire.c136
-rw-r--r--src/target/firmware/comm/Makefile5
-rw-r--r--src/target/firmware/comm/msgb.c79
-rw-r--r--src/target/firmware/comm/sercomm.c297
-rw-r--r--src/target/firmware/comm/sercomm_cons.c140
-rw-r--r--src/target/firmware/comm/timer.c215
-rw-r--r--src/target/firmware/fb/4x6.c731
-rw-r--r--src/target/firmware/fb/5x8.c802
-rw-r--r--src/target/firmware/fb/c64.c1069
-rw-r--r--src/target/firmware/fb/fb_bw8.c311
-rw-r--r--src/target/firmware/fb/fb_dummy.c70
-rw-r--r--src/target/firmware/fb/fb_rgb332.c305
-rw-r--r--src/target/firmware/fb/fb_s6b33b1x.c193
-rw-r--r--src/target/firmware/fb/fb_ssd1783.c204
-rw-r--r--src/target/firmware/fb/fb_ssd1963.c196
-rw-r--r--src/target/firmware/fb/fb_st7558.c132
-rw-r--r--src/target/firmware/fb/fb_td014.c150
-rw-r--r--src/target/firmware/fb/font.c59
-rw-r--r--src/target/firmware/fb/framebuffer.c28
-rw-r--r--src/target/firmware/fb/helvB08.c833
-rw-r--r--src/target/firmware/fb/helvB14.c1195
-rw-r--r--src/target/firmware/fb/helvB24.c1871
-rw-r--r--src/target/firmware/fb/helvR08.c826
-rw-r--r--src/target/firmware/fb/helvR14.c1198
-rw-r--r--src/target/firmware/fb/helvR24.c1870
-rw-r--r--src/target/firmware/fb/symbols.c113
-rw-r--r--src/target/firmware/flash/cfi_flash.c574
-rwxr-xr-xsrc/target/firmware/include/abb/twl3025.h186
-rw-r--r--src/target/firmware/include/arm.h7
-rw-r--r--src/target/firmware/include/arpa/inet.h2
-rw-r--r--src/target/firmware/include/asm/assembler.h113
-rw-r--r--src/target/firmware/include/asm/atomic.h106
-rw-r--r--src/target/firmware/include/asm/bitops.h225
-rw-r--r--src/target/firmware/include/asm/div64.h48
-rw-r--r--src/target/firmware/include/asm/linkage.h18
-rw-r--r--src/target/firmware/include/asm/ptrace.h128
-rw-r--r--src/target/firmware/include/asm/swab.h45
-rw-r--r--src/target/firmware/include/asm/system.h123
-rwxr-xr-xsrc/target/firmware/include/battery/battery.h37
-rw-r--r--src/target/firmware/include/battery/compal_e88.h15
-rw-r--r--src/target/firmware/include/board.h8
-rw-r--r--src/target/firmware/include/byteorder.h79
-rw-r--r--src/target/firmware/include/calypso/backlight.h10
-rw-r--r--src/target/firmware/include/calypso/buzzer.h34
-rw-r--r--src/target/firmware/include/calypso/clock.h67
-rw-r--r--src/target/firmware/include/calypso/dma.h6
-rw-r--r--src/target/firmware/include/calypso/dsp.h41
-rw-r--r--src/target/firmware/include/calypso/dsp_api.h1560
-rw-r--r--src/target/firmware/include/calypso/du.h32
-rw-r--r--src/target/firmware/include/calypso/irq.h49
-rw-r--r--src/target/firmware/include/calypso/l1_environment.h385
-rw-r--r--src/target/firmware/include/calypso/misc.h8
-rw-r--r--src/target/firmware/include/calypso/rtc.h6
-rwxr-xr-xsrc/target/firmware/include/calypso/sim.h179
-rw-r--r--src/target/firmware/include/calypso/timer.h25
-rw-r--r--src/target/firmware/include/calypso/tpu.h122
-rw-r--r--src/target/firmware/include/calypso/tsp.h31
-rw-r--r--src/target/firmware/include/comm/sercomm.h57
-rw-r--r--src/target/firmware/include/comm/sercomm_cons.h10
-rw-r--r--src/target/firmware/include/comm/timer.h77
-rw-r--r--src/target/firmware/include/console.h20
-rw-r--r--src/target/firmware/include/ctors.h16
-rw-r--r--src/target/firmware/include/ctype.h54
-rw-r--r--src/target/firmware/include/debug.h31
-rw-r--r--src/target/firmware/include/defines.h18
-rw-r--r--src/target/firmware/include/delay.h7
-rw-r--r--src/target/firmware/include/fb/fb_bw8.h51
-rw-r--r--src/target/firmware/include/fb/fb_rgb332.h47
-rw-r--r--src/target/firmware/include/fb/font.h82
-rw-r--r--src/target/firmware/include/fb/framebuffer.h128
-rw-r--r--src/target/firmware/include/flash/cfi_flash.h41
-rw-r--r--src/target/firmware/include/i2c.h7
-rw-r--r--src/target/firmware/include/keypad.h66
-rw-r--r--src/target/firmware/include/layer1/afc.h18
-rw-r--r--src/target/firmware/include/layer1/agc.h7
-rw-r--r--src/target/firmware/include/layer1/apc.h10
-rw-r--r--src/target/firmware/include/layer1/async.h62
-rw-r--r--src/target/firmware/include/layer1/avg.h23
-rw-r--r--src/target/firmware/include/layer1/l23_api.h18
-rw-r--r--src/target/firmware/include/layer1/mframe_sched.h68
-rw-r--r--src/target/firmware/include/layer1/prim.h34
-rw-r--r--src/target/firmware/include/layer1/rfch.h9
-rw-r--r--src/target/firmware/include/layer1/sched_gsmtime.h24
-rw-r--r--src/target/firmware/include/layer1/sync.h204
-rw-r--r--src/target/firmware/include/layer1/tdma_sched.h73
-rw-r--r--src/target/firmware/include/layer1/toa.h10
-rw-r--r--src/target/firmware/include/layer1/tpu_window.h24
-rw-r--r--src/target/firmware/include/manifest.h10
-rw-r--r--src/target/firmware/include/memory.h28
-rw-r--r--src/target/firmware/include/mtk/bfe.h107
-rw-r--r--src/target/firmware/include/mtk/bpi.h20
-rw-r--r--src/target/firmware/include/mtk/bsi.h41
-rw-r--r--src/target/firmware/include/mtk/emi.h42
-rw-r--r--src/target/firmware/include/mtk/mt6139.h60
-rw-r--r--src/target/firmware/include/mtk/mt6235.h74
-rw-r--r--src/target/firmware/include/mtk/mt6235_sciphone_g2.h38
-rw-r--r--src/target/firmware/include/mtk/system.h195
-rw-r--r--src/target/firmware/include/mtk/tdma_timer.h60
-rw-r--r--src/target/firmware/include/rf/trf6151.h51
-rw-r--r--src/target/firmware/include/rffe.h35
-rw-r--r--src/target/firmware/include/spi.h7
-rw-r--r--src/target/firmware/include/stdint.h36
-rw-r--r--src/target/firmware/include/stdio.h52
-rw-r--r--src/target/firmware/include/string.h12
-rw-r--r--src/target/firmware/include/swab.h297
-rw-r--r--src/target/firmware/include/uart.h32
-rw-r--r--src/target/firmware/include/uwire.h7
-rw-r--r--src/target/firmware/layer1/Makefile9
-rw-r--r--src/target/firmware/layer1/afc.c130
-rw-r--r--src/target/firmware/layer1/agc.c62
-rw-r--r--src/target/firmware/layer1/apc.c57
-rw-r--r--src/target/firmware/layer1/async.c159
-rw-r--r--src/target/firmware/layer1/avg.c57
-rw-r--r--src/target/firmware/layer1/init.c73
-rw-r--r--src/target/firmware/layer1/l23_api.c690
-rw-r--r--src/target/firmware/layer1/mframe_sched.c494
-rw-r--r--src/target/firmware/layer1/prim_fbsb.c575
-rw-r--r--src/target/firmware/layer1/prim_freq.c113
-rw-r--r--src/target/firmware/layer1/prim_pm.c241
-rw-r--r--src/target/firmware/layer1/prim_rach.c160
-rw-r--r--src/target/firmware/layer1/prim_rx_nb.c217
-rw-r--r--src/target/firmware/layer1/prim_tch.c752
-rw-r--r--src/target/firmware/layer1/prim_tx_nb.c173
-rw-r--r--src/target/firmware/layer1/prim_utils.c74
-rw-r--r--src/target/firmware/layer1/rfch.c152
-rw-r--r--src/target/firmware/layer1/sched_gsmtime.c119
-rw-r--r--src/target/firmware/layer1/sync.c402
-rw-r--r--src/target/firmware/layer1/tdma_sched.c244
-rw-r--r--src/target/firmware/layer1/toa.c80
-rw-r--r--src/target/firmware/layer1/tpu_window.c175
-rw-r--r--src/target/firmware/lib/Makefile7
-rw-r--r--src/target/firmware/lib/bitops.h33
-rw-r--r--src/target/firmware/lib/changebit.S21
-rw-r--r--src/target/firmware/lib/clearbit.S22
-rw-r--r--src/target/firmware/lib/console.c190
-rw-r--r--src/target/firmware/lib/copy_template.S255
-rw-r--r--src/target/firmware/lib/ctors.c15
-rw-r--r--src/target/firmware/lib/ctype.c34
-rw-r--r--src/target/firmware/lib/delay.c16
-rw-r--r--src/target/firmware/lib/div64.S200
-rw-r--r--src/target/firmware/lib/lib1funcs.S334
-rw-r--r--src/target/firmware/lib/memcpy.S59
-rw-r--r--src/target/firmware/lib/memset.S80
-rw-r--r--src/target/firmware/lib/printf.c19
-rw-r--r--src/target/firmware/lib/setbit.S22
-rw-r--r--src/target/firmware/lib/string.c50
-rw-r--r--src/target/firmware/lib/testchangebit.S18
-rw-r--r--src/target/firmware/lib/testclearbit.S18
-rw-r--r--src/target/firmware/lib/testsetbit.S18
-rw-r--r--src/target/firmware/lib/vsprintf.c847
-rw-r--r--src/target/firmware/rf/mt6139.c205
-rw-r--r--src/target/firmware/rf/trf6151.c605
226 files changed, 40081 insertions, 0 deletions
diff --git a/src/target/firmware/.gitignore b/src/target/firmware/.gitignore
new file mode 100644
index 00000000..79e98dfc
--- /dev/null
+++ b/src/target/firmware/.gitignore
@@ -0,0 +1,9 @@
+*.o
+*.p
+*.a
+*.lst
+*.bin
+*.elf
+*.map
+*.size
+*~
diff --git a/src/target/firmware/COPYING b/src/target/firmware/COPYING
new file mode 100644
index 00000000..d511905c
--- /dev/null
+++ b/src/target/firmware/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/target/firmware/Makefile b/src/target/firmware/Makefile
new file mode 100644
index 00000000..a71eef60
--- /dev/null
+++ b/src/target/firmware/Makefile
@@ -0,0 +1,108 @@
+
+
+# List of all supported boards (meant to be overridden on command line)
+BOARDS?=compal_e88 compal_e86 compal_e99 se_j100 gta0x pirelli_dpl10
+
+# List of all applications (meant to be overridden on command line)
+APPLICATIONS?=hello_world compal_dsp_dump layer1 loader chainload rssi
+
+# Framebuffer support, board specific drivers
+#
+
+FB_OBJS=fb/framebuffer.o fb/font.o fb/helvR08.o fb/helvB14.o fb/c64.o \
+ fb/symbols.o
+
+FB_e88_OBJS=$(FB_OBJS) fb/fb_bw8.o fb/fb_st7558.o
+FB_e99_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_ssd1783.o
+FB_e86_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_td014.o
+FB_j100_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_ssd1963.o
+FB_dpl10_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_s6b33b1x.o
+FB_dummy_OBJS=$(FB_OBJS) fb/fb_dummy.o
+
+# TI Calypso
+
+calypso_COMMON_OBJS=board/common/calypso_uart.o board/common/calypso_pwl.o
+
+# OpenMoko GTA0x
+
+gta0x_OBJS=$(calypso_COMMON_OBJS) board/gta0x/rffe_gta0x_triband.o board/gta0x/init.o \
+ board/gta0x/rf_power.o battery/dummy.o $(FB_dummy_OBJS)
+gta0x_ENVIRONMENTS=highram
+
+# Pirelli DP-L10
+
+pirelli_dpl10_OBJS=$(calypso_COMMON_OBJS) board/pirelli_dpl10/rffe_dpl10_triband.o board/pirelli_dpl10/init.o \
+ board/pirelli_dpl10/rf_power.o battery/dummy.o $(FB_dpl10_OBJS)
+pirelli_dpl10_ENVIRONMENTS=highram
+
+# Compal Generic
+
+compal_COMMON_OBJS=$(calypso_COMMON_OBJS) board/compal/rffe_dualband.o board/compal/rf_power.o
+compal_COMMON_ENVIRONMENTS=compalram highram
+
+compalram_LDS=board/compal/ram.lds
+compalram_OBJS=board/compal/start.ram.o board/compal/exceptions_redirected.o board/compal/handlers.o
+
+highram_LDS=board/compal/highram.lds
+highram_OBJS=board/compal/start.ram.o board/compal/exceptions_redirected.o board/compal/handlers.o
+
+# Compal E88
+
+compal_e88_OBJS=$(compal_COMMON_OBJS) board/compal_e88/init.o battery/compal_e88.o $(FB_e88_OBJS)
+compal_e88_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS) e88loader e88flash
+
+e88loader_LDS=board/compal_e88/loader.lds
+e88loader_OBJS=board/compal/start.rom.o board/compal/header.o board/compal/exceptions_redirect.o
+
+e88flash_LDS=board/compal_e88/flash.lds
+e88flash_OBJS=board/compal/start.rom.o board/compal/header.o board/compal/exceptions_redirected.o board/compal/handlers.o
+
+# Compal E86 (has a different RFFE configuration)
+
+compal_e86_OBJS=$(calypso_COMMON_OBJS) board/compal_e86/rffe_dualband_e86.o board/compal/rf_power.o \
+ board/compal_e86/init.o battery/dummy.o $(FB_e86_OBJS)
+compal_e86_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS)
+
+# Compal E99
+
+compal_e99_OBJS=$(compal_COMMON_OBJS) board/compal_e99/init.o battery/dummy.o $(FB_e99_OBJS)
+compal_e99_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS)
+
+e99loader_LDS=board/compal_e99/loader.lds
+e99loader_OBJS=board/compal/header.o
+e99flash_LDS=board/compal_e99/flash.lds
+
+# Sony Ericsson J100 (made by Compal)
+
+se_j100_OBJS=$(compal_COMMON_OBJS) board/se_j100/init.o battery/dummy.o $(FB_j100_OBJS)
+se_j100_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS)
+
+# Global include path
+INCLUDES=-Iinclude/ -I../../../include -I../../shared/libosmocore/include
+
+# Various objects that are currently linked into all applications
+FLASH_OBJS=flash/cfi_flash.o
+ABB_OBJS=abb/twl3025.o
+RF_OBJS=rf/trf6151.o
+
+# Objects that go in all applications
+ANY_APP_OBJS+=$(ABB_OBJS) $(RF_OBJS) $(FLASH_OBJS)
+ANY_APP_LIBS+=calypso/libcalypso.a layer1/liblayer1.a lib/libmini.a comm/libcomm.a ../../shared/libosmocore/build-target/src/.libs/libosmocore.a ../../shared/libosmocore/build-target/src/gsm/.libs/libosmogsm.a
+
+# Libraries are defined in subdirectories
+-include calypso/Makefile
+-include layer1/Makefile
+-include comm/Makefile
+-include lib/Makefile
+
+# Include rules
+-include Makefile.inc
+
+# Uncomment this line if you want to enable Tx (Transmit) Support.
+#CFLAGS += -DCONFIG_TX_ENABLE
+
+# Uncomment this line if you want to write to flash.
+#CFLAGS += -DCONFIG_FLASH_WRITE
+
+# Uncomment this line if you want to write to flash, including the bootloader.
+#CFLAGS += -DCONFIG_FLASH_WRITE_LOADER
diff --git a/src/target/firmware/Makefile.inc b/src/target/firmware/Makefile.inc
new file mode 100644
index 00000000..1f540319
--- /dev/null
+++ b/src/target/firmware/Makefile.inc
@@ -0,0 +1,208 @@
+
+#### TOOLCHAIN CONFIGURATION ####
+
+CROSS_COMPILE?=arm-elf-
+
+CC=gcc
+LD=ld
+AR=ar
+SIZE=size
+OBJCOPY=objcopy
+
+DEBUGF=dwarf-2
+
+CFLAGS=-mcpu=arm7tdmi $(INCLUDES)
+CFLAGS += -Wall -Wextra -Wcast-align -Wimplicit -Wunused
+CFLAGS += -Wswitch -Wredundant-decls -Wreturn-type -Wshadow -Wnested-externs
+CFLAGS += -Wbad-function-cast -Wsign-compare -Waggregate-return
+CFLAGS += -Os -ffunction-sections
+CFLAGS += -g$(DEBUGF)
+
+# some older toolchains don't support this, ignore it for now
+#ASFLAGS=--g$(DEBUGF) $(INCLUDES) -D__ASSEMBLY__
+ASFLAGS=$(INCLUDES) -D__ASSEMBLY__
+
+LDFLAGS = -nostartfiles -nostdlib -nodefaultlibs --gc-sections --cref
+
+#### QUIET OUTPUT ####
+
+ifndef V
+ V = 0
+endif
+
+Q_CC = $(if $(V:1=),@echo " CC $@";)
+Q_LD = $(if $(V:1=),@echo " LD $@";)
+Q_AR = $(if $(V:1=),@echo " AR $@";)
+Q_OBJ = $(if $(V:1=),@echo " OBJ $@";)
+
+#### GIT VERSION ####
+
+GIT_COMMIT:=$(shell git describe --always)
+GIT_MODIFIED:=$(shell (git status | grep "modified:\|added:\|deleted:" -q) && echo "-modified")
+
+GIT_REVISION:=$(GIT_COMMIT)$(GIT_MODIFIED)
+
+ASFLAGS += -DGIT_REVISION=\"$(GIT_REVISION)\"
+CFLAGS += -DGIT_REVISION=\"$(GIT_REVISION)\"
+
+#### GLOBAL DATA ####
+
+ALL_OBJS=
+
+ALL_LSTS=$(ALL_OBJS:.o=.lst)
+ALL_DEPS=$(ALL_OBJS:.o=.p)
+
+#### APPLICATION DATA ####
+
+ALL_APPS=
+
+ALL_APP_TARGETS=$(ALL_APPS:.elf=.bin) $(ALL_APPS:.elf=.size) $(ALL_APPS) $(ALL_APPS:.elf=.map)
+
+#### LIBRARY DATA ####
+
+ALL_LIBS=
+
+ALL_LIB_TARGETS=$(ALL_LIBS)
+
+
+#### DEFAULT RULE ####
+
+.PHONY: default
+default: all
+
+
+#### APPLICATION RULES ####
+
+# template for application rules
+define APPLICATION_BOARD_ENVIRONMENT_template
+
+# define set of objects for this binary
+$(1)_$(2)_$(3)_OBJS := apps/$(1)/main.o $(ANY_APP_OBJS) $$($(2)_OBJS)
+$(1)_$(2)_$(3)_LIBS := $(ANY_APP_LIBS)
+
+# define manifest compilation
+board/$(2)/$(1).$(3).manifest.o: board/manifest.c
+ $$(Q_CC)$(CROSS_COMPILE)$(CC) $(CFLAGS) -DAPPLICATION=\"$(1)\" -DBOARD=\"$(2)\" -DENVIRONMENT=\"$(3)\" -c -o $$@ $$<
+
+# generate dummy dependencies for manifest
+board/$(2)/$(1).$(3).manifest.p: board/manifest.c
+ @touch board/$(2)/$(1).$(3).manifest.p
+
+# add manifest object to object list
+$(1)_$(2)_$(3)_OBJS+=board/$(2)/$(1).$(3).manifest.o $$($(3)_OBJS)
+
+# define compilation rule, also generates map file
+board/$(2)/$(1).$(3).elf board/$(2)/$(1).$(3).map: $$($(1)_$(2)_$(3)_OBJS) $$($(1)_$(2)_$(3)_LIBS) $$($(3)_LDS)
+ $$(Q_LD)$(CROSS_COMPILE)$(LD) $(LDFLAGS) -T $$($(3)_LDS) -Bstatic \
+ -Map board/$(2)/$(1).$(3).map -o board/$(2)/$(1).$(3).elf \
+ --start-group $$($(1)_$(2)_$(3)_OBJS) $$($(1)_$(2)_$(3)_LIBS) --end-group
+
+# define size rule
+board/$(2)/$(1).$(3).size: board/$(2)/$(1).$(3).elf
+ $(CROSS_COMPILE)$(SIZE) board/$(2)/$(1).$(3).elf | tee board/$(2)/$(1).$(3).size
+
+ALL_APPS+=board/$(2)/$(1).$(3).elf
+ALL_OBJS+=board/$(2)/$(1).$(3).manifest.o
+
+endef
+
+define BOARD_template
+ALL_OBJS+=$$($(1)_OBJS)
+endef
+
+define BOARD_ENVIRONMENT_template
+ALL_OBJS+=$$($(1)_OBJS)
+endef
+
+define APPLICATION_template
+$(1)_SRCS_REL=$$(patsubst %,$$($(1)_DIR)/%,$$($(1)_SRCS))
+$(1)_OBJS:=$$($(1)_SRCS_REL:.c=.o)
+$(1)_OBJS:=$$($(1)_OBJS:.S=.o)
+
+ALL_OBJS+=$$($(1)_OBJS) apps/$(1)/main.o
+endef
+
+# define rules for all defined applications
+$(foreach app,$(APPLICATIONS), \
+ $(foreach brd,$(BOARDS), \
+ $(foreach env,$($(brd)_ENVIRONMENTS), \
+ $(eval $(call APPLICATION_BOARD_ENVIRONMENT_template,$(app),$(brd),$(env))))))
+
+$(foreach brd,$(BOARDS), \
+ $(eval $(call BOARD_template,$(brd)) \
+ $(foreach env,$($(brd)_ENVIRONMENTS), \
+ $(eval $(call BOARD_ENVIRONMENT_template,$(env))))))
+
+$(foreach app,$(APPLICATIONS), \
+ $(eval $(call APPLICATION_template,$(app))))
+
+
+# add common things to global lists
+ALL_OBJS+=$(ANY_APP_OBJS)
+
+#### LIBRARY RULES ####
+
+# template for library rules
+define LIBRARY_template
+
+$(1)_SRCS_REL=$$(patsubst %,$$($(1)_DIR)/%,$$($(1)_SRCS))
+$(1)_OBJS:=$$($(1)_SRCS_REL:.c=.o)
+$(1)_OBJS:=$$($(1)_OBJS:.S=.o)
+
+$$($(1)_DIR)/lib$(1).a: $$($(1)_OBJS)
+ $$(Q_AR)$(CROSS_COMPILE)$(AR) cru $$($(1)_DIR)/lib$(1).a $$($(1)_OBJS)
+
+ALL_LIBS+=$$($(1)_DIR)/lib$(1).a
+
+ALL_OBJS+=$$($(1)_OBJS)
+
+endef
+
+# define rules for all defined libraries
+$(foreach lbr,$(LIBRARIES),$(eval $(call LIBRARY_template,$(lbr))))
+
+
+#### TOPLEVEL RULES ####
+
+.PHONY: all
+all: $(ALL_DEPS) $(ALL_APPS:.elf=.bin) $(ALL_APPS:.elf=.size)
+
+.PHONY: depend
+depend: $(ALL_DEPS)
+
+
+#### COMPILATION RULES ####
+
+%.p: %.c
+ @$(CROSS_COMPILE)$(CC) $(CFLAGS) -M -o $(*).d $(<)
+ @sed 's|.*\.o:|$(@:.p=.o): |g' < $*.d > $@; rm -f $*.d; [ -s $@ ] || rm -f $@
+
+%.p: %.S
+ @$(CROSS_COMPILE)$(CC) $(ASFLAGS) -M -o $(*).d $(<)
+ @sed 's|.*\.o:|$(@:.p=.o): |g' < $*.d > $@; rm -f $*.d; [ -s $@ ] || rm -f $@
+
+%.o: %.c
+ $(Q_CC)$(CROSS_COMPILE)$(CC) $(CFLAGS) -Wa,-adhlns=$(@:.o=.lst) -c -o $@ $<
+
+%.o: %.S
+ $(Q_CC)$(CROSS_COMPILE)$(CC) $(ASFLAGS) -Wa,-adhlns=$(@:.o=.lst) -c -o $@ $<
+
+
+%.bin: %.elf
+ $(Q_OBJ)$(CROSS_COMPILE)objcopy --gap-fill=0xff -O binary $^ $@
+
+
+#### CLEANUP RULES ####
+
+.PHONY: clean
+clean:
+ rm -f $(ALL_APP_TARGETS) $(ALL_LIB_TARGETS) $(ALL_OBJS) $(ALL_DEPS) $(ALL_LSTS)
+
+.PHONY: distclean
+distclean: clean
+ find . -name '*.o' -or -name '*.bin' -or -name '*.map' -or -name '*.lst' -or -name '*.p' -exec rm '{}' ';'
+
+
+#### DEPENDENCY LOAD ####
+
+-include $(ALL_DEPS)
diff --git a/src/target/firmware/Makefile.mtk b/src/target/firmware/Makefile.mtk
new file mode 100644
index 00000000..30fa2fcf
--- /dev/null
+++ b/src/target/firmware/Makefile.mtk
@@ -0,0 +1,32 @@
+# List of all supported boards (meant to be overridden on command line)
+BOARDS?=mt62xx
+
+# List of all applications (meant to be overridden on command line)
+APPLICATIONS?=loader_mtk
+
+mtkram_LDS=board/mediatek/ram.lds
+mtkram_OBJS=board/mediatek/start.ram.o
+
+mtk_COMMON_OBJS=board/mediatek/uart.o
+
+# Mediatek MT62xx
+mt62xx_OBJS=$(mtk_COMMON_OBJS) board/mt62xx/init.o
+mt62xx_ENVIRONMENTS=mtkram
+
+# Global include path
+INCLUDES=-Iinclude/ -I../../../include -I../../shared/libosmocore/include
+
+FLASH_OBJS=flash/cfi_flash.o
+
+# Objects that go in all applications
+ANY_APP_OBJS+=$(FLASH_OBJS)
+
+# Various objects that are currently linked into all applications
+ANY_APP_LIBS+=lib/libmini.a comm/libcomm.a ../../shared/libosmocore/build-target/src/.libs/libosmocore.a
+
+# Libraries are defined in subdirectories
+-include comm/Makefile
+-include lib/Makefile
+
+# Include rules
+-include Makefile.inc
diff --git a/src/target/firmware/abb/twl3025.c b/src/target/firmware/abb/twl3025.c
new file mode 100644
index 00000000..e4fcf4f0
--- /dev/null
+++ b/src/target/firmware/abb/twl3025.c
@@ -0,0 +1,368 @@
+/* Driver for Analog Baseband Circuit (TWL3025) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <delay.h>
+#include <memory.h>
+#include <spi.h>
+#include <calypso/irq.h>
+#include <calypso/tsp.h>
+#include <calypso/tpu.h>
+#include <abb/twl3025.h>
+#include <asm/system.h>
+
+/* TWL3025 */
+#define REG_PAGE(n) (n >> 7)
+#define REG_ADDR(n) (n & 0x3f)
+
+#define TWL3025_DEV_IDX 0 /* On the SPI bus */
+#define TWL3025_TSP_DEV_IDX 0 /* On the TSP bus */
+
+/* values encountered on a GTA-02 for GSM900 (the same for GSM1800!?) */
+const uint16_t twl3025_default_ramp[16] = {
+ ABB_RAMP_VAL( 0, 0),
+ ABB_RAMP_VAL( 0, 11),
+ ABB_RAMP_VAL( 0, 31),
+ ABB_RAMP_VAL( 0, 31),
+ ABB_RAMP_VAL( 0, 31),
+ ABB_RAMP_VAL( 0, 24),
+ ABB_RAMP_VAL( 0, 0),
+ ABB_RAMP_VAL( 0, 0),
+ ABB_RAMP_VAL( 9, 0),
+ ABB_RAMP_VAL(18, 0),
+ ABB_RAMP_VAL(25, 0),
+ ABB_RAMP_VAL(31, 0),
+ ABB_RAMP_VAL(30, 0),
+ ABB_RAMP_VAL(15, 0),
+ ABB_RAMP_VAL( 0, 0),
+ ABB_RAMP_VAL( 0, 0),
+};
+
+struct twl3025 {
+ uint8_t page;
+};
+static struct twl3025 twl3025_state;
+
+/* Switch the register page of the TWL3025 */
+static void twl3025_switch_page(uint8_t page)
+{
+ if (page == 0)
+ twl3025_reg_write(PAGEREG, 1 << 0);
+ else
+ twl3025_reg_write(PAGEREG, 1 << 1);
+
+ twl3025_state.page = page;
+}
+
+static void handle_charger(void)
+{
+ uint16_t status;
+ printd("handle_charger();");
+
+ status = twl3025_reg_read(VRPCSTS);
+// printd("\nvrpcsts: 0x%02x", status);
+
+ if (status & 0x40) {
+ printd(" inserted\n");
+ } else {
+ printd(" removed\n");
+ }
+
+// twl3025_dump_madc();
+}
+
+static void handle_adc_done(void)
+{
+ printd("handle_adc_done();");
+}
+
+static void twl3025_irq(enum irq_nr nr)
+{
+ uint16_t src;
+ printd("twl3025_irq: 0x%02x\n",nr);
+ switch (nr){
+ case IRQ_EXTERNAL: // charger in/out, pwrbtn, adc done
+ src = twl3025_reg_read(ITSTATREG);
+// printd("itstatreg 0x%02x\n", src);
+ if (src & 0x08)
+ handle_charger();
+ if (src & 0x20)
+ handle_adc_done();
+ break;
+ case IRQ_EXTERNAL_FIQ: // vcc <2.8V emergency power off
+ puts("\nBROWNOUT!1!");
+ twl3025_power_off();
+ break;
+ default:
+ return;
+ }
+}
+
+void twl3025_init(void)
+{
+ spi_init();
+ twl3025_switch_page(0);
+ twl3025_clk13m(1);
+ twl3025_reg_write(AFCCTLADD, 0x01); /* AFCCK(1:0) must not be zero! */
+ twl3025_unit_enable(TWL3025_UNIT_AFC, 1);
+
+ irq_register_handler(IRQ_EXTERNAL, &twl3025_irq);
+ irq_config(IRQ_EXTERNAL, 0, 0, 0);
+ irq_enable(IRQ_EXTERNAL);
+
+ irq_register_handler(IRQ_EXTERNAL_FIQ, &twl3025_irq);
+ irq_config(IRQ_EXTERNAL_FIQ, 1, 0, 0);
+ irq_enable(IRQ_EXTERNAL_FIQ);
+}
+
+void twl3025_reg_write(uint8_t reg, uint16_t data)
+{
+ uint16_t tx;
+
+ printd("tw3025_reg_write(%u,%u)=0x%04x\n", REG_PAGE(reg),
+ REG_ADDR(reg), data);
+
+ if (reg != PAGEREG && REG_PAGE(reg) != twl3025_state.page)
+ twl3025_switch_page(REG_PAGE(reg));
+
+ tx = ((data & 0x3ff) << 6) | (REG_ADDR(reg) << 1);
+
+ spi_xfer(TWL3025_DEV_IDX, 16, &tx, NULL);
+}
+
+void twl3025_tsp_write(uint8_t data)
+{
+ tsp_write(TWL3025_TSP_DEV_IDX, 7, data);
+}
+
+uint16_t twl3025_reg_read(uint8_t reg)
+{
+ uint16_t tx, rx;
+
+ if (REG_PAGE(reg) != twl3025_state.page)
+ twl3025_switch_page(REG_PAGE(reg));
+
+ tx = (REG_ADDR(reg) << 1) | 1;
+
+ /* A read cycle contains two SPI transfers */
+ spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx);
+ delay_ms(1);
+ spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx);
+
+ rx >>= 6;
+
+ printd("tw3025_reg_read(%u,%u)=0x%04x\n", REG_PAGE(reg),
+ REG_ADDR(reg), rx);
+
+ return rx;
+}
+
+static void twl3025_wait_ibic_access(void)
+{
+ /* Wait 6 * 32kHz clock cycles for first IBIC access (187us + 10% = 210us) */
+ delay_ms(1);
+}
+
+void twl3025_power_off(void)
+{
+ unsigned long flags;
+
+ /* turn off all IRQs, since received frames cannot be
+ * handled form here. (otherwise the message allocation
+ * runs out of memory) */
+ local_firq_save(flags);
+
+ /* poll PWON status and power off the phone when the
+ * powerbutton has been released (otherwise it will
+ * poweron immediately again) */
+ while (!(twl3025_reg_read(VRPCSTS) & 0x10)) { };
+ twl3025_reg_write(VRPCDEV, 0x01);
+}
+
+void twl3025_clk13m(int enable)
+{
+ if (enable) {
+ twl3025_reg_write(TOGBR2, TOGBR2_ACTS);
+ twl3025_wait_ibic_access();
+ /* for whatever reason we need to do this twice */
+ twl3025_reg_write(TOGBR2, TOGBR2_ACTS);
+ twl3025_wait_ibic_access();
+ } else {
+ twl3025_reg_write(TOGBR2, TOGBR2_ACTR);
+ twl3025_wait_ibic_access();
+ }
+}
+
+#define TSP_DELAY 6 /* 13* Tclk6M5 = ~ 3 GSM Qbits + 3 TPU instructions */
+#define BDLON_TO_BDLCAL 6
+#define BDLCAL_DURATION 66
+#define BDLON_TO_BDLENA 7
+#define BULON_TO_BULENA 16
+#define BULON_TO_BULCAL 17
+#define BULCAL_DURATION 143 /* really that long? */
+
+/* bdl_ena - TSP_DELAY - BDLCAL_DURATION - TSP_DELAY - BDLON_TO_BDLCAL - TSP_DELAY */
+#define DOWNLINK_DELAY (3 * TSP_DELAY + BDLCAL_DURATION + BDLON_TO_BDLCAL)
+
+/* Enqueue a series of TSP commands in the TPU to (de)activate the downlink path */
+void twl3025_downlink(int on, int16_t at)
+{
+ int16_t bdl_ena = at - TSP_DELAY - 6;
+
+ if (on) {
+ if (bdl_ena < 0)
+ printf("BDLENA time negative (%d)\n", bdl_ena);
+ /* calibration should be done just before BDLENA */
+ tpu_enq_at(bdl_ena - DOWNLINK_DELAY);
+ /* bdl_ena - TSP_DELAY - BDLCAL_DURATION - TSP_DELAY - BDLON_TO_BDLCAL - TSP_DELAY */
+ twl3025_tsp_write(BDLON);
+ /* bdl_ena - TSP_DELAY - BDLCAL_DURATION - TSP_DELAY - BDLON_TO_BDLCAL */
+ tpu_enq_wait(BDLON_TO_BDLCAL - TSP_DELAY);
+ /* bdl_ena - TSP_DELAY - BDLCAL_DURATION - TSP_DELAY */
+ twl3025_tsp_write(BDLON | BDLCAL);
+ /* bdl_ena - TSP_DELAY - BDLCAL_DURATION */
+ tpu_enq_wait(BDLCAL_DURATION - TSP_DELAY);
+ /* bdl_ena - TSP_DELAY */
+ twl3025_tsp_write(BDLON);
+ //tpu_enq_wait(BDLCAL_TO_BDLENA) this is only 3.7us == 4 qbits, i.e. less than the TSP_DELAY
+ tpu_enq_at(bdl_ena);
+ twl3025_tsp_write(BDLON | BDLENA);
+ } else {
+ tpu_enq_at(bdl_ena);
+ twl3025_tsp_write(BDLON);
+ //tpu_enq_wait(nBDLENA_TO_nBDLON) this is only 3.7us == 4 qbits, i.e. less than the TSP_DELAY
+ twl3025_tsp_write(0);
+ }
+}
+
+/* bdl_ena - 35 - TSP_DELAY - BULCAL_DURATION - TSP_DELAY - BULON_TO_BULCAL - TSP_DELAY */
+#define UPLINK_DELAY (3 * TSP_DELAY + BULCAL_DURATION + BULON_TO_BULCAL + 35)
+
+void twl3025_uplink(int on, int16_t at)
+{
+ int16_t bul_ena = at - TSP_DELAY - 6;
+
+ if (bul_ena < 0)
+ printf("BULENA time negative (%d)\n", bul_ena);
+ if (on) {
+ /* calibration should be done just before BULENA */
+ tpu_enq_at(bul_ena - UPLINK_DELAY);
+ /* bdl_ena - 35 - TSP_DELAY - BULCAL_DURATION - TSP_DELAY - BULON_TO_BULCAL - TSP_DELAY */
+ twl3025_tsp_write(BULON);
+ /* bdl_ena - 35 - TSP_DELAY - BULCAL_DURATION - TSP_DELAY - BULON_TO_BULCAL */
+ tpu_enq_wait(BULON_TO_BULCAL - TSP_DELAY);
+ /* bdl_ena - 35 - TSP_DELAY - BULCAL_DURATION - TSP_DELAY */
+ twl3025_tsp_write(BULON | BULCAL);
+ /* bdl_ena - 35 - TSP_DELAY - BULCAL_DURATION */
+ tpu_enq_wait(BULCAL_DURATION - TSP_DELAY);
+ /* bdl_ena - 35 - TSP_DELAY */
+ twl3025_tsp_write(BULON);
+ /* bdl_ena - 35 */
+ tpu_enq_wait(35); /* minimum time required to bring the ramp up (really needed?) */
+ tpu_enq_at(bul_ena);
+ twl3025_tsp_write(BULON | BULENA);
+ } else {
+ tpu_enq_at(bul_ena);
+ twl3025_tsp_write(BULON);
+ tpu_enq_wait(35); /* minimum time required to bring the ramp down (needed!) */
+ twl3025_tsp_write(0);
+ }
+}
+
+void twl3025_afc_set(int16_t val)
+{
+ printf("twl3025_afc_set(%d)\n", val);
+
+ if (val > 4095)
+ val = 4095;
+ else if (val <= -4096)
+ val = -4096;
+
+ /* FIXME: we currently write from the USP rather than BSP */
+ twl3025_reg_write(AUXAFC2, val >> 10);
+ twl3025_reg_write(AUXAFC1, val & 0x3ff);
+}
+
+int16_t twl3025_afc_get(void)
+{
+ int16_t val;
+
+ val = (twl3025_reg_read(AUXAFC2) & 0x7);
+ val = val << 10;
+ val = val | (twl3025_reg_read(AUXAFC1) & 0x3ff);
+
+ if (val > 4095)
+ val = -(8192 - val);
+ return val;
+}
+
+void twl3025_unit_enable(enum twl3025_unit unit, int on)
+{
+ uint16_t togbr1 = 0;
+
+ switch (unit) {
+ case TWL3025_UNIT_AFC:
+ if (on)
+ togbr1 = (1 << 7);
+ else
+ togbr1 = (1 << 6);
+ break;
+ case TWL3025_UNIT_MAD:
+ if (on)
+ togbr1 = (1 << 9);
+ else
+ togbr1 = (1 << 8);
+ break;
+ case TWL3025_UNIT_ADA:
+ if (on)
+ togbr1 = (1 << 5);
+ else
+ togbr1 = (1 << 4);
+ case TWL3025_UNIT_VDL:
+ if (on)
+ togbr1 = (1 << 3);
+ else
+ togbr1 = (1 << 2);
+ break;
+ case TWL3025_UNIT_VUL:
+ if (on)
+ togbr1 = (1 << 1);
+ else
+ togbr1 = (1 << 0);
+ break;
+ }
+ twl3025_reg_write(TOGBR1, togbr1);
+}
+
+uint8_t twl3025_afcout_get(void)
+{
+ return twl3025_reg_read(AFCOUT) & 0xff;
+}
+
+void twl3025_afcout_set(uint8_t val)
+{
+ twl3025_reg_write(AFCCTLADD, 0x05);
+ twl3025_reg_write(AFCOUT, val);
+}
diff --git a/src/target/firmware/apps/chainload/main.c b/src/target/firmware/apps/chainload/main.c
new file mode 100644
index 00000000..9dfa2176
--- /dev/null
+++ b/src/target/firmware/apps/chainload/main.c
@@ -0,0 +1,54 @@
+/* Compal ramloader -> Calypso romloader Chainloading application */
+
+/* (C) 2010 by Steve Markgraf <steve@steve-m.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <delay.h>
+
+#include <calypso/clock.h>
+#include <calypso/timer.h>
+
+/* Main Program */
+
+static void device_enter_loader(unsigned char bootrom) {
+ calypso_bootrom(bootrom);
+ void (*entry)( void ) = (void (*)(void))0;
+ entry();
+}
+
+int main(void)
+{
+ /* Always disable wdt (some platforms enable it on boot) */
+ wdog_enable(0);
+
+ /* enable Calypso romloader mapping and jump there */
+ delay_ms(200);
+ device_enter_loader(1);
+
+ /* Not reached */
+ while(1) {
+ }
+}
diff --git a/src/target/firmware/apps/compal_dsp_dump/main.c b/src/target/firmware/apps/compal_dsp_dump/main.c
new file mode 100644
index 00000000..ba48790f
--- /dev/null
+++ b/src/target/firmware/apps/compal_dsp_dump/main.c
@@ -0,0 +1,85 @@
+/* main program of Free Software for Calypso Phone */
+
+/* (C) 2010 Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <memory.h>
+#include <delay.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/irq.h>
+#include <calypso/misc.h>
+#include <comm/timer.h>
+#include <fb/framebuffer.h>
+
+/* Main Program */
+const char *hr = "======================================================================\n";
+
+int main(void)
+{
+ board_init();
+
+ puts("\n\nOsmocomBB Compal DSP Dumper (revision " GIT_REVISION ")\n");
+ puts(hr);
+
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ fb_clear();
+
+ fb_setfg(FB_COLOR_BLACK);
+ fb_setbg(FB_COLOR_WHITE);
+ fb_setfont(FB_FONT_HELVB14);
+
+ fb_gotoxy(2,20);
+ fb_putstr("DSP Dump",framebuffer->width-4);
+
+ fb_setfg(FB_COLOR_RED);
+ fb_setbg(FB_COLOR_BLUE);
+
+ fb_gotoxy(2,25);
+ fb_boxto(framebuffer->width-3,38);
+
+ fb_setfg(FB_COLOR_WHITE);
+ fb_setfont(FB_FONT_HELVR08);
+ fb_gotoxy(8,33);
+ fb_putstr("osmocom-bb",framebuffer->width-4);
+
+ fb_flush();
+
+ /* Dump DSP content */
+ dsp_dump();
+
+ while (1) {
+ osmo_timers_update();
+ }
+}
+
diff --git a/src/target/firmware/apps/hello_world/main.c b/src/target/firmware/apps/hello_world/main.c
new file mode 100644
index 00000000..02cab050
--- /dev/null
+++ b/src/target/firmware/apps/hello_world/main.c
@@ -0,0 +1,199 @@
+/* main program of Free Software for Calypso Phone */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <delay.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/irq.h>
+#include <calypso/misc.h>
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+#include <fb/framebuffer.h>
+#include <battery/battery.h>
+
+/* Main Program */
+const char *hr = "======================================================================\n";
+
+void key_handler(enum key_codes code, enum key_states state);
+
+static void console_rx_cb(uint8_t dlci, struct msgb *msg)
+{
+ if (dlci != SC_DLCI_CONSOLE) {
+ printf("Message for unknown DLCI %u\n", dlci);
+ return;
+ }
+
+ printf("Message on console DLCI: '%s'\n", msg->data);
+ msgb_free(msg);
+}
+
+static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
+{
+ int i;
+ puts("l1a_l23_rx_cb: ");
+ for (i = 0; i < msg->len; i++)
+ printf("%02x ", msg->data[i]);
+ puts("\n");
+}
+
+void
+write_battery_info(void *p){
+ char buf[128];
+
+ fb_setfg(FB_COLOR_WHITE);
+ fb_setfont(FB_FONT_C64);
+
+ snprintf(buf,sizeof(buf),"B: %04d mV",battery_info.bat_volt_mV);
+ fb_gotoxy(8,41);
+ fb_putstr(buf,framebuffer->width-8);
+
+ snprintf(buf,sizeof(buf),"C: %04d mV",battery_info.charger_volt_mV);
+ fb_gotoxy(8,49);
+ fb_putstr(buf,framebuffer->width-8);
+
+ snprintf(buf,sizeof(buf),"F: %08x",battery_info.flags);
+ fb_gotoxy(8,57);
+ fb_putstr(buf,framebuffer->width-8);
+
+ fb_flush();
+ osmo_timer_schedule((struct osmo_timer_list*)p,100);
+
+}
+
+/* timer that fires the charging loop regularly */
+static struct osmo_timer_list write_battery_info_timer = {
+ .cb = &write_battery_info,
+ .data = &write_battery_info_timer
+};
+
+int main(void)
+{
+ board_init();
+
+ puts("\n\nOsmocomBB Hello World (revision " GIT_REVISION ")\n");
+ puts(hr);
+
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ /* Dump clock config before PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ keypad_set_handler(&key_handler);
+
+ /* Dump clock config after PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ fb_clear();
+
+ fb_setfg(FB_COLOR_BLACK);
+ fb_setbg(FB_COLOR_WHITE);
+ fb_setfont(FB_FONT_HELVB14);
+
+ fb_gotoxy(2,20);
+ fb_putstr("Hello World!",framebuffer->width-4);
+
+ fb_setfg(FB_COLOR_RED);
+ fb_setbg(FB_COLOR_BLUE);
+
+ fb_gotoxy(2,25);
+ fb_boxto(framebuffer->width-3,38);
+
+ fb_setfg(FB_COLOR_WHITE);
+ fb_setfont(FB_FONT_HELVR08);
+ fb_gotoxy(8,33);
+ fb_putstr("osmocom-bb",framebuffer->width-4);
+
+ fb_flush();
+
+
+
+ /* Dump all memory */
+ //dump_mem();
+#if 0
+ /* Dump Bootloader */
+ memdump_range((void *)0x00000000, 0x2000);
+ puts(hr);
+#endif
+
+ sercomm_register_rx_cb(SC_DLCI_CONSOLE, console_rx_cb);
+ sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
+
+ osmo_timer_schedule(&write_battery_info_timer,100);
+
+ /* beyond this point we only react to interrupts */
+ puts("entering interrupt loop\n");
+ while (1) {
+ osmo_timers_update();
+ }
+
+ twl3025_power_off();
+
+ while (1) {}
+}
+
+void key_handler(enum key_codes code, enum key_states state)
+{
+ char test[16];
+
+ if (state != PRESSED)
+ return;
+
+ switch (code) {
+ case KEY_0:
+ case KEY_1:
+ case KEY_2:
+ case KEY_3:
+ case KEY_4:
+ case KEY_5:
+ case KEY_6:
+ case KEY_7:
+ case KEY_8:
+ case KEY_9:
+ // used to be display_puts...
+ break;
+ case KEY_STAR:
+ // used to be display puts...
+ break;
+ case KEY_HASH:
+ // used to be display puts...
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/target/firmware/apps/layer1/main.c b/src/target/firmware/apps/layer1/main.c
new file mode 100644
index 00000000..6a78bef8
--- /dev/null
+++ b/src/target/firmware/apps/layer1/main.c
@@ -0,0 +1,173 @@
+/* main program of Free Software for Calypso Phone */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <string.h>
+#include <delay.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/irq.h>
+#include <calypso/misc.h>
+#include <calypso/sim.h>
+
+#include <layer1/sync.h>
+#include <layer1/async.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+
+#include <fb/framebuffer.h>
+
+const char *hr = "======================================================================\n";
+
+/* MAIN program **************************************************************/
+
+static void key_handler(enum key_codes code, enum key_states state);
+
+int main(void)
+{
+ uint8_t atr[20];
+ uint8_t atrLength = 0;
+
+ board_init();
+
+ puts("\n\nOsmocomBB Layer 1 (revision " GIT_REVISION ")\n");
+ puts(hr);
+
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ keypad_set_handler(&key_handler);
+
+ /* Dump clock config after PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ fb_clear();
+
+ fb_setfg(FB_COLOR_BLACK);
+ fb_setbg(FB_COLOR_WHITE);
+ fb_setfont(FB_FONT_HELVB14);
+
+ fb_gotoxy(2,20);
+ fb_putstr("Layer 1",framebuffer->width-4);
+
+ fb_setfg(FB_COLOR_RED);
+ fb_setbg(FB_COLOR_BLUE);
+
+ fb_gotoxy(2,25);
+ fb_boxto(framebuffer->width-3,38);
+
+ fb_setfg(FB_COLOR_WHITE);
+ fb_setfont(FB_FONT_HELVR08);
+ fb_gotoxy(8,33);
+ fb_putstr("osmocom-bb",framebuffer->width-4);
+
+ fb_flush();
+
+ /* initialize SIM */
+ calypso_sim_init();
+
+ puts("Power up simcard:\n");
+ memset(atr,0,sizeof(atr));
+ atrLength = calypso_sim_powerup(atr);
+
+ layer1_init();
+
+ tpu_frame_irq_en(1, 1);
+
+ while (1) {
+ l1a_compl_execute();
+ osmo_timers_update();
+ sim_handler();
+ l1a_l23_handler();
+ }
+
+ /* NOT REACHED */
+
+ twl3025_power_off();
+}
+
+static int afcout = 0;
+
+static void tspact_toggle(uint8_t num)
+{
+ printf("TSPACT%u toggle\n", num);
+ tsp_act_toggle((1 << num));
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+}
+
+static void key_handler(enum key_codes code, enum key_states state)
+{
+ if (state != PRESSED)
+ return;
+
+ switch (code) {
+ case KEY_4:
+ tspact_toggle(6); /* TRENA (RFFE) */
+ break;
+ case KEY_5:
+ tspact_toggle(8); /* GSM_TXEN (RFFE) */
+ break;
+ case KEY_6:
+ tspact_toggle(1); /* PAENA (RFFE) */
+ break;
+ case KEY_7: /* decrement AFC OUT */
+ afcout -= 100;
+ if (afcout < -4096)
+ afcout = -4096;
+ twl3025_afc_set(afcout);
+ printf("AFC OUT: %u\n", twl3025_afcout_get());
+ break;
+ case KEY_9: /* increase AFC OUT */
+ afcout += 100;
+ if (afcout > 4095)
+ afcout = 4095;
+ twl3025_afc_set(afcout);
+ printf("AFC OUT: %u\n", twl3025_afcout_get());
+ break;
+ default:
+ break;
+ }
+ /* power down SIM, TODO: this will happen with every key pressed,
+ put it somewhere else ! */
+ calypso_sim_powerdown();
+}
+
+
diff --git a/src/target/firmware/apps/loader/main.c b/src/target/firmware/apps/loader/main.c
new file mode 100644
index 00000000..50a39ddd
--- /dev/null
+++ b/src/target/firmware/apps/loader/main.c
@@ -0,0 +1,445 @@
+/* boot loader for Calypso phones */
+
+/* (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <delay.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+#include <console.h>
+#include <manifest.h>
+
+#include <osmocom/core/crc16.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+
+#include <comm/sercomm.h>
+
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/irq.h>
+#include <calypso/misc.h>
+#include <calypso/backlight.h>
+#include <uart.h>
+#include <calypso/timer.h>
+
+#include <flash/cfi_flash.h>
+
+#include "protocol.h"
+
+/* Main Program */
+const char *hr =
+ "======================================================================\n";
+
+static void key_handler(enum key_codes code, enum key_states state);
+static void cmd_handler(uint8_t dlci, struct msgb *msg);
+
+int flag = 0;
+
+static void flush_uart(void)
+{
+ unsigned i;
+ for (i = 0; i < 500; i++) {
+ uart_poll(SERCOMM_UART_NR);
+ delay_ms(1);
+ }
+}
+
+static void device_poweroff(void)
+{
+ flush_uart();
+ twl3025_power_off();
+}
+
+static void device_reset(void)
+{
+ flush_uart();
+ wdog_reset();
+}
+
+static void device_enter_loader(unsigned char bootrom)
+{
+ flush_uart();
+
+ calypso_bootrom(bootrom);
+ void (*entry) (void) = (void (*)(void))0;
+ entry();
+}
+
+static void device_jump(void *entry)
+{
+ flush_uart();
+
+ void (*f) (void) = (void (*)(void))entry;
+ f();
+}
+
+static void loader_send_simple(struct msgb *msg, uint8_t dlci, uint8_t command)
+{
+ msgb_put_u8(msg, command);
+ sercomm_sendmsg(dlci, msg);
+}
+
+extern unsigned char _start;
+
+static void loader_send_init(uint8_t dlci)
+{
+ struct msgb *msg = sercomm_alloc_msgb(9);
+ msgb_put_u8(msg, LOADER_INIT);
+ msgb_put_u32(msg, 0);
+ msgb_put_u32(msg, &_start);
+ sercomm_sendmsg(dlci, msg);
+}
+
+flash_t the_flash;
+
+extern void putchar_asm(uint32_t c);
+
+static const uint8_t phone_ack[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x42 };
+
+int main(void)
+{
+ /* Simulate a compal loader saying "ACK" */
+ int i = 0;
+ for (i = 0; i < sizeof(phone_ack); i++) {
+ putchar_asm(phone_ack[i]);
+ }
+
+ /* Always disable wdt (some platforms enable it on boot) */
+ wdog_enable(0);
+
+ /* Disable the bootrom mapping */
+ calypso_bootrom(0);
+
+ /* Initialize TWL3025 for power control */
+ twl3025_init();
+
+ /* Backlight */
+ bl_mode_pwl(1);
+ bl_level(50);
+
+ /* Initialize UART without interrupts */
+ uart_init(SERCOMM_UART_NR, 0);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+
+ /* Initialize HDLC subsystem */
+ sercomm_init();
+
+ /* Say hi */
+ puts("\n\nOsmocomBB Loader (revision " GIT_REVISION ")\n");
+ puts(hr);
+
+ /* Identify environment */
+ printf("Running on %s in environment %s\n", manifest_board,
+ manifest_environment);
+
+ /* Initialize flash driver */
+ if (flash_init(&the_flash, 0)) {
+ puts("Failed to initialize flash!\n");
+ } else {
+ printf("Found flash of %d bytes at 0x%x with %d regions\n",
+ the_flash.f_size, the_flash.f_base,
+ the_flash.f_nregions);
+
+ int i;
+ for (i = 0; i < the_flash.f_nregions; i++) {
+ printf(" Region %d of %d pages with %d bytes each.\n",
+ i,
+ the_flash.f_regions[i].fr_bnum,
+ the_flash.f_regions[i].fr_bsize);
+ }
+
+ }
+
+ /* Set up a key handler for powering off */
+ keypad_set_handler(&key_handler);
+
+ /* Set up loader communications */
+ sercomm_register_rx_cb(SC_DLCI_LOADER, &cmd_handler);
+
+ /* Notify any running osmoload about our startup */
+ loader_send_init(SC_DLCI_LOADER);
+
+ /* Wait for events */
+ while (1) {
+ keypad_poll();
+ uart_poll(SERCOMM_UART_NR);
+ }
+
+ /* NOT REACHED */
+
+ twl3025_power_off();
+}
+
+static void cmd_handler(uint8_t dlci, struct msgb *msg)
+{
+ if (msg->data_len < 1) {
+ return;
+ }
+
+ uint8_t command = msgb_pull_u8(msg);
+
+ int res;
+
+ flash_lock_t lock;
+
+ void *data;
+
+ uint8_t chip;
+ uint8_t nbytes;
+ uint16_t crc, mycrc;
+ uint32_t address;
+
+ struct msgb *reply = sercomm_alloc_msgb(256); // XXX
+
+ if (!reply) {
+ printf("Failed to allocate reply buffer!\n");
+ goto out;
+ }
+
+ switch (command) {
+
+ case LOADER_PING:
+ loader_send_simple(reply, dlci, LOADER_PING);
+ break;
+
+ case LOADER_RESET:
+ loader_send_simple(reply, dlci, LOADER_RESET);
+ device_reset();
+ break;
+
+ case LOADER_POWEROFF:
+ loader_send_simple(reply, dlci, LOADER_POWEROFF);
+ device_poweroff();
+ break;
+
+ case LOADER_ENTER_ROM_LOADER:
+ loader_send_simple(reply, dlci, LOADER_ENTER_ROM_LOADER);
+ device_enter_loader(1);
+ break;
+
+ case LOADER_ENTER_FLASH_LOADER:
+ loader_send_simple(reply, dlci, LOADER_ENTER_FLASH_LOADER);
+ device_enter_loader(0);
+ break;
+
+ case LOADER_MEM_READ:
+
+ nbytes = msgb_pull_u8(msg);
+ address = msgb_pull_u32(msg);
+
+ crc = osmo_crc16(0, (void *)address, nbytes);
+
+ msgb_put_u8(reply, LOADER_MEM_READ);
+ msgb_put_u8(reply, nbytes);
+ msgb_put_u16(reply, crc);
+ msgb_put_u32(reply, address);
+
+ memcpy(msgb_put(reply, nbytes), (void *)address, nbytes);
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_MEM_WRITE:
+
+ nbytes = msgb_pull_u8(msg);
+ crc = msgb_pull_u16(msg);
+ address = msgb_pull_u32(msg);
+
+ data = msgb_pull(msg, nbytes);
+
+ mycrc = osmo_crc16(0, data, nbytes);
+
+ if (mycrc == crc) {
+ memcpy((void *)address, data, nbytes);
+ }
+
+ msgb_put_u8(reply, LOADER_MEM_WRITE);
+ msgb_put_u8(reply, nbytes);
+ msgb_put_u16(reply, mycrc);
+ msgb_put_u32(reply, address);
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_JUMP:
+
+ address = msgb_pull_u32(msg);
+
+ msgb_put_u8(reply, LOADER_JUMP);
+ msgb_put_u32(reply, address);
+
+ sercomm_sendmsg(dlci, reply);
+
+ device_jump((void *)address);
+
+ break;
+
+ case LOADER_FLASH_INFO:
+
+ msgb_put_u8(reply, LOADER_FLASH_INFO);
+ msgb_put_u8(reply, 1); // nchips
+
+ // chip 1
+ msgb_put_u32(reply, the_flash.f_base);
+ msgb_put_u32(reply, the_flash.f_size);
+ msgb_put_u8(reply, the_flash.f_nregions);
+
+ int i;
+ for (i = 0; i < the_flash.f_nregions; i++) {
+ msgb_put_u32(reply, the_flash.f_regions[i].fr_bnum);
+ msgb_put_u32(reply, the_flash.f_regions[i].fr_bsize);
+ }
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_FLASH_ERASE:
+ case LOADER_FLASH_UNLOCK:
+ case LOADER_FLASH_LOCK:
+ case LOADER_FLASH_LOCKDOWN:
+
+ chip = msgb_pull_u8(msg);
+ address = msgb_pull_u32(msg);
+
+ if (command == LOADER_FLASH_ERASE) {
+ res = flash_block_erase(&the_flash, address);
+ }
+ if (command == LOADER_FLASH_UNLOCK) {
+ res = flash_block_unlock(&the_flash, address);
+ }
+ if (command == LOADER_FLASH_LOCK) {
+ res = flash_block_lock(&the_flash, address);
+ }
+ if (command == LOADER_FLASH_LOCKDOWN) {
+ res = flash_block_lockdown(&the_flash, address);
+ }
+
+ msgb_put_u8(reply, command);
+ msgb_put_u8(reply, chip);
+ msgb_put_u32(reply, address);
+ msgb_put_u32(reply, (res != 0));
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_FLASH_GETLOCK:
+
+ chip = msgb_pull_u8(msg);
+ address = msgb_pull_u32(msg);
+
+ lock = flash_block_getlock(&the_flash, address);
+
+ msgb_put_u8(reply, command);
+ msgb_put_u8(reply, chip);
+ msgb_put_u32(reply, address);
+
+ switch (lock) {
+ case FLASH_UNLOCKED:
+ msgb_put_u32(reply, LOADER_FLASH_UNLOCKED);
+ break;
+ case FLASH_LOCKED:
+ msgb_put_u32(reply, LOADER_FLASH_LOCKED);
+ break;
+ case FLASH_LOCKED_DOWN:
+ msgb_put_u32(reply, LOADER_FLASH_LOCKED_DOWN);
+ break;
+ default:
+ msgb_put_u32(reply, 0xFFFFFFFF);
+ break;
+ }
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_FLASH_PROGRAM:
+
+ nbytes = msgb_pull_u8(msg);
+ crc = msgb_pull_u16(msg);
+ msgb_pull_u8(msg); // XXX align
+ chip = msgb_pull_u8(msg);
+ address = msgb_pull_u32(msg);
+
+ data = msgb_pull(msg, nbytes);
+
+ mycrc = osmo_crc16(0, data, nbytes);
+
+ if (mycrc == crc) {
+ res = flash_program(&the_flash, address, data, nbytes);
+ }
+
+ msgb_put_u8(reply, LOADER_FLASH_PROGRAM);
+ msgb_put_u8(reply, nbytes);
+ msgb_put_u16(reply, mycrc);
+ msgb_put_u8(reply, 0); // XXX align
+ msgb_put_u8(reply, chip);
+ msgb_put_u32(reply, address);
+
+ msgb_put_u32(reply, (uint32_t) res); // XXX
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ default:
+ printf("unknown command %d\n", command);
+
+ msgb_free(reply);
+
+ break;
+ }
+
+ out:
+
+ msgb_free(msg);
+}
+
+static void key_handler(enum key_codes code, enum key_states state)
+{
+ if (state != PRESSED)
+ return;
+
+ switch (code) {
+ case KEY_POWER:
+ puts("Powering off due to keypress.\n");
+ device_poweroff();
+ break;
+ case KEY_OK:
+ puts("Resetting due to keypress.\n");
+ device_reset();
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/target/firmware/apps/loader/protocol.h b/src/target/firmware/apps/loader/protocol.h
new file mode 100644
index 00000000..0a61c89e
--- /dev/null
+++ b/src/target/firmware/apps/loader/protocol.h
@@ -0,0 +1,37 @@
+
+enum loader_command {
+ /* init message from loader */
+ LOADER_INIT,
+
+ /* ping / pong */
+ LOADER_PING,
+
+ /* lifecycle requests */
+ LOADER_RESET,
+ LOADER_POWEROFF,
+
+ /* jumps */
+ LOADER_JUMP,
+ LOADER_ENTER_ROM_LOADER,
+ LOADER_ENTER_FLASH_LOADER,
+
+ /* generic memory ops */
+ LOADER_MEM_READ,
+ LOADER_MEM_WRITE,
+
+ /* flash operations */
+ LOADER_FLASH_INFO,
+ LOADER_FLASH_ERASE,
+ LOADER_FLASH_UNLOCK,
+ LOADER_FLASH_LOCK,
+ LOADER_FLASH_LOCKDOWN,
+ LOADER_FLASH_GETLOCK,
+ LOADER_FLASH_PROGRAM,
+
+};
+
+enum loader_flash_lock {
+ LOADER_FLASH_UNLOCKED = 0,
+ LOADER_FLASH_LOCKED,
+ LOADER_FLASH_LOCKED_DOWN,
+};
diff --git a/src/target/firmware/apps/loader_mtk/main.c b/src/target/firmware/apps/loader_mtk/main.c
new file mode 100644
index 00000000..7748dc45
--- /dev/null
+++ b/src/target/firmware/apps/loader_mtk/main.c
@@ -0,0 +1,366 @@
+/*
+ * boot loader for MTK phones (based on the calypso-version)
+ *
+ * (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ * (C) 2011 by Wolfram Sang <wolfram@the-dreams.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <delay.h>
+#include <keypad.h>
+#include <board.h>
+#include <console.h>
+#include <defines.h>
+#include <manifest.h>
+
+#include <osmocom/core/crc16.h>
+
+#include <comm/sercomm.h>
+
+#include <uart.h>
+
+#include <flash/cfi_flash.h>
+
+#include <mtk/emi.h>
+#include <mtk/mt6235.h>
+#include <mtk/system.h>
+
+#include "../loader/protocol.h"
+
+/* Main Program */
+const char *hr =
+ "======================================================================\n";
+
+static void cmd_handler(uint8_t dlci, struct msgb *msg);
+
+int flag = 0;
+
+static void flush_uart(void)
+{
+ unsigned i;
+ for (i = 0; i < 500; i++) {
+ uart_poll(SERCOMM_UART_NR);
+ delay_ms(1);
+ }
+}
+
+static void device_poweroff(void)
+{
+ flush_uart();
+ writew(BBPU_MAGIC | RTC_BBPU_WRITE_EN,
+ MTK_RTC_BBPU);
+ writew(1, MTK_RTC_WRTGR);
+}
+
+static void device_reset(void)
+{
+ flush_uart();
+}
+
+static void device_enter_loader(__unused unsigned char bootrom)
+{
+ flush_uart();
+ delay_ms(2000);
+ void (*entry)( void ) = (void (*)(void))0;
+ entry();
+}
+
+static void device_jump(void *entry)
+{
+ flush_uart();
+
+ void (*f) (void) = (void (*)(void))entry;
+ f();
+}
+
+static void loader_send_simple(struct msgb *msg, uint8_t dlci, uint8_t command)
+{
+ msgb_put_u8(msg, command);
+ sercomm_sendmsg(dlci, msg);
+}
+
+extern unsigned char _start;
+
+flash_t the_flash;
+
+extern void putchar_asm(uint32_t c);
+
+static const uint8_t phone_ack[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x42 };
+
+int main(void)
+{
+ board_init ();
+
+ /* Initialize HDLC subsystem */
+ sercomm_init();
+
+ /* Say hi */
+ puts("\n\nOsmocomBB Loader (revision " GIT_REVISION ")\n");
+ puts(hr);
+
+ /* Identify environment */
+ printf("\nRunning on %s in environment %s\n", manifest_board,
+ manifest_environment);
+
+ printf("\nHW_CODE = 0x%04x", readw(MTK_CONFG_HW_CODE));
+
+ /* Set up loader communications */
+ sercomm_register_rx_cb(SC_DLCI_LOADER, &cmd_handler);
+
+ /* Wait for events */
+
+ while (1) {
+ uart_poll(SERCOMM_UART_NR);
+ }
+
+}
+
+static void cmd_handler(uint8_t dlci, struct msgb *msg)
+{
+ if (msg->data_len < 1) {
+ return;
+ }
+
+ uint8_t command = msgb_pull_u8(msg);
+
+ int res;
+
+ flash_lock_t lock;
+
+ void *data;
+
+ uint8_t chip;
+ uint8_t nbytes;
+ uint16_t crc, mycrc;
+ uint32_t address;
+
+ struct msgb *reply = sercomm_alloc_msgb(256); // XXX
+
+ if (!reply) {
+ printf("Failed to allocate reply buffer!\n");
+ goto out;
+ }
+
+ switch (command) {
+
+ case LOADER_PING:
+ loader_send_simple(reply, dlci, LOADER_PING);
+ break;
+
+ case LOADER_RESET:
+ loader_send_simple(reply, dlci, LOADER_RESET);
+ device_reset();
+ break;
+
+ case LOADER_POWEROFF:
+ loader_send_simple(reply, dlci, LOADER_POWEROFF);
+ device_poweroff();
+ break;
+
+ case LOADER_ENTER_ROM_LOADER:
+ loader_send_simple(reply, dlci, LOADER_ENTER_ROM_LOADER);
+ device_enter_loader(1);
+ break;
+
+ case LOADER_ENTER_FLASH_LOADER:
+ loader_send_simple(reply, dlci, LOADER_ENTER_FLASH_LOADER);
+ device_enter_loader(0);
+ break;
+
+ case LOADER_MEM_READ:
+
+ nbytes = msgb_pull_u8(msg);
+ address = msgb_pull_u32(msg);
+
+ crc = osmo_crc16(0, (void *)address, nbytes);
+
+ msgb_put_u8(reply, LOADER_MEM_READ);
+ msgb_put_u8(reply, nbytes);
+ msgb_put_u16(reply, crc);
+ msgb_put_u32(reply, address);
+
+ memcpy(msgb_put(reply, nbytes), (void *)address, nbytes);
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_MEM_WRITE:
+
+ nbytes = msgb_pull_u8(msg);
+ crc = msgb_pull_u16(msg);
+ address = msgb_pull_u32(msg);
+
+ data = msgb_pull(msg, nbytes);
+
+ mycrc = osmo_crc16(0, data, nbytes);
+
+ if (mycrc == crc) {
+ memcpy((void *)address, data, nbytes);
+ }
+
+ msgb_put_u8(reply, LOADER_MEM_WRITE);
+ msgb_put_u8(reply, nbytes);
+ msgb_put_u16(reply, mycrc);
+ msgb_put_u32(reply, address);
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_JUMP:
+
+ address = msgb_pull_u32(msg);
+
+ msgb_put_u8(reply, LOADER_JUMP);
+ msgb_put_u32(reply, address);
+
+ sercomm_sendmsg(dlci, reply);
+
+ device_jump((void *)address);
+
+ break;
+
+ case LOADER_FLASH_INFO:
+
+ msgb_put_u8(reply, LOADER_FLASH_INFO);
+ msgb_put_u8(reply, 1); // nchips
+
+ // chip 1
+ msgb_put_u32(reply, the_flash.f_base);
+ msgb_put_u32(reply, the_flash.f_size);
+ msgb_put_u8(reply, the_flash.f_nregions);
+
+ unsigned i;
+ for (i = 0; i < the_flash.f_nregions; i++) {
+ msgb_put_u32(reply, the_flash.f_regions[i].fr_bnum);
+ msgb_put_u32(reply, the_flash.f_regions[i].fr_bsize);
+ }
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_FLASH_ERASE:
+ case LOADER_FLASH_UNLOCK:
+ case LOADER_FLASH_LOCK:
+ case LOADER_FLASH_LOCKDOWN:
+
+ chip = msgb_pull_u8(msg);
+ address = msgb_pull_u32(msg);
+
+ if (command == LOADER_FLASH_ERASE) {
+ res = flash_block_erase(&the_flash, address);
+ }
+ if (command == LOADER_FLASH_UNLOCK) {
+ res = flash_block_unlock(&the_flash, address);
+ }
+ if (command == LOADER_FLASH_LOCK) {
+ res = flash_block_lock(&the_flash, address);
+ }
+ if (command == LOADER_FLASH_LOCKDOWN) {
+ res = flash_block_lockdown(&the_flash, address);
+ }
+
+ msgb_put_u8(reply, command);
+ msgb_put_u8(reply, chip);
+ msgb_put_u32(reply, address);
+ msgb_put_u32(reply, (res != 0));
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_FLASH_GETLOCK:
+
+ chip = msgb_pull_u8(msg);
+ address = msgb_pull_u32(msg);
+
+ lock = flash_block_getlock(&the_flash, address);
+
+ msgb_put_u8(reply, command);
+ msgb_put_u8(reply, chip);
+ msgb_put_u32(reply, address);
+
+ switch (lock) {
+ case FLASH_UNLOCKED:
+ msgb_put_u32(reply, LOADER_FLASH_UNLOCKED);
+ break;
+ case FLASH_LOCKED:
+ msgb_put_u32(reply, LOADER_FLASH_LOCKED);
+ break;
+ case FLASH_LOCKED_DOWN:
+ msgb_put_u32(reply, LOADER_FLASH_LOCKED_DOWN);
+ break;
+ default:
+ msgb_put_u32(reply, 0xFFFFFFFF);
+ break;
+ }
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ case LOADER_FLASH_PROGRAM:
+
+ nbytes = msgb_pull_u8(msg);
+ crc = msgb_pull_u16(msg);
+ msgb_pull_u8(msg); // XXX align
+ chip = msgb_pull_u8(msg);
+ address = msgb_pull_u32(msg);
+
+ data = msgb_pull(msg, nbytes);
+
+ mycrc = osmo_crc16(0, data, nbytes);
+
+ if (mycrc == crc) {
+ res = flash_program(&the_flash, address, data, nbytes);
+ }
+
+ msgb_put_u8(reply, LOADER_FLASH_PROGRAM);
+ msgb_put_u8(reply, nbytes);
+ msgb_put_u16(reply, mycrc);
+ msgb_put_u8(reply, 0); // XXX align
+ msgb_put_u8(reply, chip);
+ msgb_put_u32(reply, address);
+
+ msgb_put_u32(reply, (uint32_t) res); // XXX
+
+ sercomm_sendmsg(dlci, reply);
+
+ break;
+
+ default:
+ printf("unknown command %d\n", command);
+
+ msgb_free(reply);
+
+ break;
+ }
+
+ out:
+
+ msgb_free(msg);
+}
diff --git a/src/target/firmware/apps/rssi/main.c b/src/target/firmware/apps/rssi/main.c
new file mode 100644
index 00000000..b2cafae4
--- /dev/null
+++ b/src/target/firmware/apps/rssi/main.c
@@ -0,0 +1,1562 @@
+/* Cell Monitor of Free Software for Calypso Phone */
+
+/* (C) 2012 by Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <delay.h>
+#include <byteorder.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/irq.h>
+#include <calypso/misc.h>
+#include <calypso/buzzer.h>
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+#include <fb/framebuffer.h>
+#include <layer1/sync.h>
+#include <layer1/async.h>
+#include <layer1/l23_api.h>
+#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/gsm48_ie.h>
+#include <battery/battery.h>
+
+enum key_codes key_code = KEY_INV;
+int key_pressed = 0;
+enum key_codes key_pressed_code;
+unsigned long key_pressed_when;
+unsigned int key_pressed_delay;
+
+enum mode {
+ MODE_MAIN,
+ MODE_SPECTRUM,
+ MODE_ARFCN,
+ MODE_SYNC,
+ MODE_RACH,
+} mode = MODE_MAIN;
+enum mode last_mode; /* where to return after entering ARFCN */
+
+static uint16_t arfcn = 0, ul_arfcn;
+int pcs = 0;
+int uplink = 0;
+int max = 0;
+uint8_t power, max_power;
+char input[5];
+int cursor;
+
+char *sync_result = NULL;
+char *sync_msg = "";
+
+static struct band {
+ int min, max, prev, next, freq_ul, freq_dl;
+} bands[] = {
+ { 128, 251, 124, 512, 8242, 8692 }, /* GSM 850 */
+ { 955, 124, 885, 128, 8762, 9212 }, /* P,E,R GSM */
+ { 512, 885, 251, 955, 17102, 18052 }, /* DCS 1800 */
+ { 0, 0, 0, 0, 0, 0},
+};
+
+struct band *band;
+
+#define PCS_MIN 512
+#define PCS_MAX 810
+#define DCS_MIN 512
+#define DCS_MAX 885
+#define PCS_UL 18502
+#define PCS_DL 19302
+
+enum pm_mode {
+ PM_IDLE,
+ PM_SENT,
+ PM_RANGE_SENT,
+ PM_RANGE_RESULT,
+ PM_RESULT,
+} pm_mode = PM_IDLE;
+
+#define NUM_PM_DL 2
+#define NUM_PM_UL 10
+int pm_meas[NUM_PM_UL];
+int pm_count = 0;
+int pm_max = 2;
+uint8_t pm_spectrum[1024];
+int pm_scale = 1; /* scale measured power level */
+
+#define TONE_JIFFIES ((HZ < 25) ? 1 : HZ / 25)
+int tone = 0;
+unsigned long tone_time;
+int tone_on = 0;
+
+uint8_t bsic;
+uint8_t ul_levels[8], ul_max[8]; /* 8 uplink levels */
+uint8_t si_1[23];
+uint8_t si_2[23];
+uint8_t si_2bis[23];
+uint8_t si_2ter[23];
+uint8_t si_3[23];
+uint8_t si_4[23];
+uint16_t si_new = 0, ul_new;
+uint16_t mcc, mnc, lac, cell_id;
+int ccch_conf;
+int nb_num;
+struct gsm_sysinfo_freq freq[1024];
+#define NEIGH_LINES ((framebuffer->height - 25) / 8)
+
+#define FREQ_TYPE_SERV 0x01 /* frequency of the serving cell */
+#define FREQ_TYPE_NCELL 0x1c /* frequency of the neighbor cell */
+#define FREQ_TYPE_NCELL_2 0x04 /* sub channel of SI 2 */
+#define FREQ_TYPE_NCELL_2bis 0x08 /* sub channel of SI 2bis */
+#define FREQ_TYPE_NCELL_2ter 0x10 /* sub channel of SI 2ter */
+
+int rach = 0;
+struct gsm48_req_ref rach_ref;
+uint8_t rach_ra;
+unsigned long rach_when;
+uint8_t ta;
+
+enum assign {
+ ASSIGN_NONE,
+ ASSIGN_NO_TX,
+ ASSIGN_RESULT,
+ ASSIGN_REJECT,
+ ASSIGN_TIMEOUT,
+} assign;
+
+/* UI */
+
+static void print_display(char *text, int *y, int c)
+{
+ /* skip lines, given by cursor */
+ (*y)++;
+ if (c >= (*y))
+ return;
+ /* skip, if end of display area is reached */
+ if ((*y) - c > NEIGH_LINES)
+ return;
+
+ fb_gotoxy(0, 20 + (((*y) - c - 1) << 3));
+ fb_putstr(text, framebuffer->width);
+}
+
+static void refresh_display(void)
+{
+ char text[16];
+ int bat = battery_info.battery_percent;
+
+ fb_clear();
+
+ /* header */
+ fb_setbg(FB_COLOR_WHITE);
+ if (mode != MODE_SPECTRUM && !(mode == MODE_SYNC && cursor < 0)) {
+ fb_setfg(FB_COLOR_BLUE);
+ fb_setfont(FB_FONT_HELVR08);
+ fb_gotoxy(0, 7);
+ fb_putstr("Osmocom RSSI", -1);
+ fb_setfg(FB_COLOR_RGB(0xc0, 0xc0, 0x00));
+ fb_setfont(FB_FONT_SYMBOLS);
+ fb_gotoxy(framebuffer->width - 15, 8);
+ if (bat >= 100 && (battery_info.flags & BATTERY_CHG_ENABLED)
+ && !(battery_info.flags & BATTERY_CHARGING))
+ fb_putstr("@HHBC", framebuffer->width);
+ else {
+ sprintf(text, "@%c%c%cC", (bat >= 30) ? 'B':'A',
+ (bat >= 60) ? 'B':'A', (bat >= 90) ? 'B':'A');
+ fb_putstr(text, framebuffer->width);
+ }
+ fb_gotoxy(0, 8);
+ sprintf(text, "%c%cE%c%c", (power >= 40) ? 'D':'G',
+ (power >= 10) ? 'D':'G', (power >= 10) ? 'F':'G',
+ (power >= 40) ? 'F':'G');
+ fb_putstr(text, framebuffer->width);
+ fb_setfg(FB_COLOR_GREEN);
+ fb_gotoxy(0, 10);
+ fb_boxto(framebuffer->width - 1, 10);
+ }
+ fb_setfg(FB_COLOR_BLACK);
+ fb_setfont(FB_FONT_C64);
+
+ /* RACH */
+ if (mode == MODE_RACH) {
+ unsigned long elapsed = jiffies - rach_when;
+
+ fb_gotoxy(0,28);
+ switch (assign) {
+ case ASSIGN_NONE:
+ fb_putstr("Rach sent...", -1);
+ break;
+ case ASSIGN_RESULT:
+ sprintf(text, "TA = %d", ta);
+ fb_putstr(text, -1);
+ fb_gotoxy(0,36);
+ sprintf(text, "(%dm)", ta * 554);
+ fb_putstr(text, -1);
+ break;
+ case ASSIGN_REJECT:
+ fb_putstr("Rejected!", -1);
+ break;
+ case ASSIGN_NO_TX:
+ fb_putstr("TX disabled", -1);
+ break;
+ case ASSIGN_TIMEOUT:
+ fb_putstr("Timeout", -1);
+ break;
+ }
+ switch (assign) {
+ case ASSIGN_RESULT:
+ case ASSIGN_REJECT:
+ fb_gotoxy(0,44);
+ sprintf(text, "Delay:%ldms", elapsed * 1000 / HZ);
+ fb_putstr(text, -1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* SYNC / UL levels */
+ if (mode == MODE_SYNC && cursor < 0) {
+ int i, tn, l;
+ int offset = (framebuffer->width - 96) >> 1;
+ int height = framebuffer->height - 25;
+
+ fb_setfont(FB_FONT_HELVR08);
+ for (i = 0; i < 8; i++) {
+ if (uplink)
+ tn = (i + 3) & 7; /* UL is shifted by 3 */
+ else
+ tn = i;
+ fb_setbg(FB_COLOR_WHITE);
+ fb_gotoxy(offset + 12 * i, 7);
+ l = (max) ? ul_max[tn] : ul_levels[tn];
+ l = 110 - l;
+ if (l >= 100)
+ l -= 100;
+ sprintf(text, "%02d", l);
+ fb_putstr(text, framebuffer->width);
+ fb_setbg(FB_COLOR_BLACK);
+ fb_gotoxy(offset + 3 + 12 * i, height + 10);
+ fb_boxto(offset + 3 + 12 * i + 5, height + 10 - ul_levels[tn] * height / 64);
+ if (max) {
+ fb_gotoxy(offset + 3 + 12 * i, height + 10 - ul_max[tn] * height / 64);
+ fb_boxto(offset + 3 + 12 * i + 5, height + 10 - ul_max[tn] * height / 64);
+ }
+ }
+ fb_setbg(FB_COLOR_TRANSP);
+ if (max) {
+ fb_setfg(FB_COLOR_RED);
+ fb_gotoxy(framebuffer->width - 16, 15);
+ fb_putstr("max", framebuffer->width);
+ }
+ fb_setfont(FB_FONT_C64);
+ fb_setfg(FB_COLOR_BLUE);
+ fb_gotoxy(0, 16);
+ if (pcs && ul_arfcn >= PCS_MIN && ul_arfcn <= PCS_MAX)
+ sprintf(text, "%4dP", ul_arfcn);
+ else if (ul_arfcn >= DCS_MIN && ul_arfcn <= DCS_MAX)
+ sprintf(text, "%4dD", ul_arfcn);
+ else
+ sprintf(text, "%4d ", ul_arfcn);
+ fb_putstr(text, framebuffer->width);
+ fb_setbg(FB_COLOR_WHITE);
+ fb_setfg(FB_COLOR_BLACK);
+ }
+
+ /* SYNC / SI */
+ if (mode == MODE_SYNC && cursor == 0) {
+ fb_gotoxy(0, 20);
+ if (sync_msg[0] == 'o')
+ sprintf(text, "BSIC%d/%d %4d", bsic >> 3, bsic & 7,
+ power - 110);
+ else
+ sprintf(text, "Sync %s", sync_msg);
+ fb_putstr(text, -1);
+
+ fb_gotoxy(0,28);
+ text[0] = si_1[2] ? '1' : '-';
+ text[1] = ' ';
+ text[2] = si_2[2] ? '2' : '-';
+ text[3] = ' ';
+ text[4] = si_2bis[2] ? '2' : '-';
+ text[5] = si_2bis[2] ? 'b' : ' ';
+ text[6] = si_2ter[2] ? '2' : '-';
+ text[7] = si_2ter[2] ? 't' : ' ';
+ text[8] = ' ';
+ text[9] = si_3[2] ? '3' : '-';
+ text[10] = ' ';
+ text[11] = si_4[2] ? '4' : '-';
+ text[12] = '\0';
+ fb_putstr(text, -1);
+
+ fb_gotoxy(0, 36);
+ fb_putstr("MCC MNC LAC ", -1);
+ fb_gotoxy(0, 44);
+ if (mcc) {
+ if ((mnc & 0x00f) == 0x00f)
+ sprintf(text, "%3x %02x %04x", mcc, mnc >> 4, lac);
+ else
+ sprintf(text, "%3x %03x %04x", mcc, mnc, lac);
+ fb_putstr(text, -1);
+ } else
+ fb_putstr("--- --- ----", -1);
+ fb_gotoxy(0, 52);
+ if (si_3[2]) {
+ sprintf(text, "cell id:%04x", cell_id);
+ fb_putstr(text, -1);
+ } else
+ fb_putstr("cell id:----", -1);
+ }
+
+ /* SYNC / neighbour cells */
+ if (mode == MODE_SYNC && cursor > 0) {
+ int i, y = 0;
+
+ text[0] = '\0';
+ for (i = 0; i < 1024; i++) {
+ if (freq[i].mask & FREQ_TYPE_SERV) {
+ if (!text[0])
+ sprintf(text, "S: %4d", i);
+ else {
+ sprintf(text + 7, " %4d", i);
+ print_display(text, &y, cursor - 1);
+ text[0] = '\0';
+ }
+ }
+ }
+ if (text[0])
+ print_display(text, &y, cursor - 1);
+ text[0] = '\0';
+ for (i = 0; i < 1024; i++) {
+ if (freq[i].mask & FREQ_TYPE_NCELL) {
+ if (!text[0])
+ sprintf(text, "N: %4d", i);
+ else {
+ sprintf(text + 7, " %4d", i);
+ print_display(text, &y, cursor - 1);
+ text[0] = '\0';
+ }
+ }
+ }
+ if (text[0])
+ print_display(text, &y, cursor - 1);
+ nb_num = y;
+ }
+
+ /* ARFCN */
+ if (mode == MODE_MAIN || mode == MODE_ARFCN) {
+ fb_gotoxy(0, 20);
+ if (mode == MODE_ARFCN)
+ sprintf(text, "ARFCN %s", input);
+ else if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX)
+ sprintf(text, "ARFCN %dPCS", arfcn);
+ else if (arfcn >= DCS_MIN && arfcn <= DCS_MAX)
+ sprintf(text, "ARFCN %dDCS", arfcn);
+ else
+ sprintf(text, "ARFCN %d", arfcn);
+ fb_putstr(text,framebuffer->width);
+ }
+
+ /* cursor */
+ if (mode == MODE_ARFCN) {
+ fb_setfg(FB_COLOR_WHITE);
+ fb_setbg(FB_COLOR_BLUE);
+ fb_putstr(" ", framebuffer->width);
+ fb_setfg(FB_COLOR_BLACK);
+ fb_setbg(FB_COLOR_WHITE);
+ }
+
+ /* Frequency / power */
+ if (mode == MODE_MAIN) {
+ int f;
+
+ if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX) {
+ if (uplink)
+ f = PCS_UL;
+ else
+ f = PCS_DL;
+ } else if (uplink)
+ f = band->freq_ul;
+ else
+ f = band->freq_dl;
+ f += ((arfcn - band->min) & 1023) << 1;
+
+ fb_gotoxy(0, 30);
+ sprintf(text, "Freq. %d.%d", f / 10, f % 10);
+ fb_putstr(text,framebuffer->width);
+
+ fb_gotoxy(0, 40);
+ sprintf(text, "Power %d", ((max) ? max_power : power) - 110);
+ fb_putstr(text, framebuffer->width);
+ if (max) {
+ fb_setfont(FB_FONT_HELVR08);
+ fb_setfg(FB_COLOR_RED);
+ fb_gotoxy(framebuffer->width - 16, 39);
+ fb_putstr("max", framebuffer->width);
+ fb_setfont(FB_FONT_C64);
+ fb_setfg(FB_COLOR_BLACK);
+ }
+ fb_setbg(FB_COLOR_BLACK);
+ fb_gotoxy(0, 45);
+ fb_boxto(framebuffer->width * power / 64, 50);
+ if (max) {
+ fb_gotoxy(framebuffer->width * max_power / 64 ,45);
+ fb_boxto(framebuffer->width * max_power / 64, 50);
+ }
+ fb_setbg(FB_COLOR_WHITE);
+ }
+
+ /* spectrum */
+ if (mode == MODE_SPECTRUM) {
+ int i;
+ uint16_t a, e, p;
+ int height = framebuffer->height - 25;
+
+ fb_gotoxy(0, 8);
+ if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX)
+ sprintf(text, "%4dP", arfcn);
+ else if (arfcn >= DCS_MIN && arfcn <= DCS_MAX)
+ sprintf(text, "%4dD", arfcn);
+ else
+ sprintf(text, "%4d ", arfcn);
+ sprintf(text + 5, " %4d", pm_spectrum[arfcn & 1023] - 110);
+ fb_putstr(text, -1);
+ fb_setfg(FB_COLOR_RED);
+ if (max) {
+ fb_setfont(FB_FONT_HELVR08);
+ fb_gotoxy(framebuffer->width - 16,15);
+ fb_putstr("max", framebuffer->width);
+ fb_setfont(FB_FONT_C64);
+ }
+ if (pm_scale != 1) {
+ fb_setfont(FB_FONT_HELVR08);
+ fb_gotoxy(1, 15);
+ sprintf(text, "x%d", pm_scale);
+ fb_putstr(text, framebuffer->width);
+ fb_setfont(FB_FONT_C64);
+ }
+ fb_setfg(FB_COLOR_BLACK);
+ if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX) {
+ a = PCS_MIN;
+ e = PCS_MAX;
+ } else {
+ a = band->min;
+ e = band->max;
+ }
+ for (i = 0; i < framebuffer->width; i++) {
+ p = (arfcn + i - (framebuffer->width >> 1)) & 1023;
+ if ((((p - a) & 1023) & 512))
+ continue;
+ if ((((e - p) & 1023) & 512))
+ continue;
+ p = (pm_spectrum[p] * pm_scale * height / 64);
+ if (p > height)
+ p = height;
+ if (i == (framebuffer->width >> 1))
+ fb_setfg(FB_COLOR_RED);
+ fb_gotoxy(i, height + 10 - p);
+ fb_boxto(i, height + 10);
+ if (i == (framebuffer->width >> 1))
+ fb_setfg(FB_COLOR_BLACK);
+ }
+ i = framebuffer->width >> 1;
+ fb_gotoxy(i, 0);
+ fb_boxto(i, 4);
+ fb_gotoxy(i, height + 10);
+ fb_boxto(i, height + 14);
+ }
+
+ /* footer */
+ fb_setfg(FB_COLOR_GREEN);
+ fb_gotoxy(0, framebuffer->height - 10);
+ fb_boxto(framebuffer->width-1, framebuffer->height - 10);
+ fb_gotoxy(0, framebuffer->height - 1);
+ fb_setfg(FB_COLOR_RED);
+ if (mode == MODE_ARFCN)
+ sprintf(text, "%s %s", (cursor) ? "del " : "back",
+ (cursor) ? "enter" : " ");
+ else if (mode == MODE_SYNC && cursor < 0)
+ sprintf(text, "%s %s", "back",
+ (uplink) ? "UL" : "DL");
+ else if (mode == MODE_SYNC || mode == MODE_RACH)
+ sprintf(text, "%s ", "back");
+ else
+ sprintf(text, "%s %s", (pcs) ? "PCS" : "DCS",
+ (uplink) ? "UL" : "DL");
+ fb_putstr(text, -1);
+ fb_setfg(FB_COLOR_BLACK);
+ fb_setfont(FB_FONT_HELVR08);
+ fb_gotoxy(0, framebuffer->height - 2);
+ sprintf(text, "%d", tone / 25);
+ fb_putstr(text, -1);
+
+ fb_flush();
+}
+
+static void exit_arfcn(void)
+{
+ mode = last_mode;
+ refresh_display();
+}
+
+static void enter_arfcn(enum key_codes code)
+{
+ /* enter mode */
+ if (mode != MODE_ARFCN) {
+ last_mode = mode;
+ mode = MODE_ARFCN;
+ input[0] = code - KEY_0 + '0';
+ input[1] = '\0';
+ cursor = 1;
+ refresh_display();
+ return;
+ }
+
+ if (code == KEY_LEFT_SB) {
+ /* back */
+ if (cursor == 0) {
+ exit_arfcn();
+ return;
+ }
+ /* delete */
+ cursor--;
+ input[cursor] = '\0';
+ refresh_display();
+ return;
+ }
+
+ if (code == KEY_RIGHT_SB) {
+ int check = 0;
+ int i;
+ struct band *temp = NULL;
+
+ /* nothing entered */
+ if (cursor == 0) {
+ return;
+ }
+ for (i = 0; i < cursor; i++)
+ check = (check << 3) + (check << 1) + input[i] - '0';
+
+ /* check */
+ for (i = 0; bands[i].max; i++) {
+ temp = &bands[i];
+ if (temp->min < temp->max) {
+ if (check >= temp->min && check <= temp->max)
+ break;
+ } else {
+ if (check >= temp->min || check <= temp->max)
+ break;
+ }
+ }
+ if (!bands[i].max)
+ return;
+ if (check > 1023)
+ return;
+ arfcn = check;
+ band = temp;
+ mode = last_mode;
+ refresh_display();
+ return;
+ }
+
+ if (cursor == 4)
+ return;
+
+ input[cursor] = code - KEY_0 + '0';
+ cursor++;
+ input[cursor] = '\0';
+ refresh_display();
+}
+
+static int inc_dec_arfcn(int inc)
+{
+ int i;
+
+ /* select current band */
+ for (i = 0; bands[i].max; i++) {
+ band = &bands[i];
+ if (band->min < band->max) {
+ if (arfcn >= band->min && arfcn <= band->max)
+ break;
+ } else {
+ if (arfcn >= band->min || arfcn <= band->max)
+ break;
+ }
+ }
+ if (!bands[i].max)
+ return -EINVAL;
+
+ if (inc) {
+ if (arfcn == band->max)
+ arfcn = band->next;
+ else if (arfcn == 1023)
+ arfcn = 0;
+ else
+ arfcn++;
+ } else {
+ if (arfcn == band->min)
+ arfcn = band->prev;
+ else if (arfcn == 0)
+ arfcn = 1023;
+ else
+ arfcn--;
+ }
+ /* select next band */
+ for (i = 0; bands[i].max; i++) {
+ band = &bands[i];
+ if (band->min < band->max) {
+ if (arfcn >= band->min && arfcn <= band->max)
+ break;
+ } else {
+ if (arfcn >= band->min || arfcn <= band->max)
+ break;
+ }
+ }
+ if (!bands[i].max)
+ return -EINVAL;
+
+ refresh_display();
+
+ return 0;
+}
+
+static void request_ul_levels(uint16_t a);
+
+static int inc_dec_ul_arfcn(int inc)
+{
+ uint16_t a;
+
+ /* loop until we hit a serving cell or our current bcch arfcn */
+ if (inc) {
+ for (a = (ul_arfcn + 1) & 1023; a != (arfcn & 1023);
+ a = (a + 1) & 1023) {
+ if ((freq[a].mask & FREQ_TYPE_SERV))
+ break;
+ }
+ } else {
+ for (a = (ul_arfcn - 1) & 1023; a != (arfcn & 1023);
+ a = (a - 1) & 1023) {
+ if ((freq[a].mask & FREQ_TYPE_SERV))
+ break;
+ }
+ }
+ ul_arfcn = a;
+
+ refresh_display();
+
+ request_ul_levels(a);
+
+ return 0;
+}
+
+static void toggle_dcs_pcs(void)
+{
+ pcs = !pcs;
+ refresh_display();
+}
+
+static void toggle_up_down(void)
+{
+ uplink = !uplink;
+ refresh_display();
+
+ if (mode == MODE_SYNC && cursor < 0)
+ request_ul_levels(ul_arfcn);
+}
+
+static void toggle_spectrum(void)
+{
+ if (mode == MODE_MAIN) {
+ mode = MODE_SPECTRUM;
+ pm_mode = PM_IDLE;
+ } else if (mode == MODE_SPECTRUM) {
+ mode = MODE_MAIN;
+ pm_mode = PM_IDLE;
+ }
+ l1s_reset();
+ l1s_reset_hw();
+ pm_count = 0;
+ refresh_display();
+}
+
+static void tone_inc_dec(int inc)
+{
+ if (inc) {
+ if (tone + 25 <= 255)
+ tone += 25;
+ } else {
+ if (tone - 25 >= 0)
+ tone -= 25;
+ }
+
+ refresh_display();
+}
+
+static void hold_max(void)
+{
+ max = !max;
+ max_power = power;
+ refresh_display();
+}
+
+static int inc_dec_neighbour(int inc)
+{
+ if (inc) {
+ if (cursor > 0 && cursor - 1 >= (nb_num - NEIGH_LINES))
+ return -EINVAL;
+ cursor++;
+ } else {
+ if (cursor < 0)
+ return -EINVAL;
+ cursor--;
+ }
+
+ refresh_display();
+
+ return 0;
+}
+
+static int inc_dec_spectrum(int inc)
+{
+ if (inc) {
+ pm_scale <<= 1;
+ if (pm_scale > 8)
+ pm_scale = 8;
+ } else {
+ pm_scale >>= 1;
+ if (pm_scale < 1)
+ pm_scale = 1;
+ }
+
+ refresh_display();
+
+ return 0;
+}
+
+static void enter_sync(void);
+static void exit_sync(void);
+
+static void enter_rach(void);
+static void exit_rach(void);
+
+static void handle_key_code()
+{
+ /* key repeat */
+ if (key_pressed) {
+ unsigned long elapsed = jiffies - key_pressed_when;
+ if (elapsed > key_pressed_delay) {
+ key_pressed_when = jiffies;
+ key_pressed_delay = HZ / 10;
+ /* only repeat these keys */
+ if (key_pressed_code == KEY_LEFT
+ || key_pressed_code == KEY_RIGHT)
+ key_code = key_pressed_code;
+ }
+ }
+
+ if (key_code == KEY_INV)
+ return;
+
+ /* do later, do not disturb tone */
+ if (tone_on)
+ return;
+
+ switch (key_code) {
+ case KEY_0:
+ case KEY_1:
+ case KEY_2:
+ case KEY_3:
+ case KEY_4:
+ case KEY_5:
+ case KEY_6:
+ case KEY_7:
+ case KEY_8:
+ case KEY_9:
+ if (mode == MODE_MAIN || mode == MODE_SPECTRUM || mode == MODE_ARFCN)
+ enter_arfcn(key_code);
+ break;
+ case KEY_UP:
+ if (mode == MODE_MAIN)
+ tone_inc_dec(1);
+ else if (mode == MODE_SYNC)
+ inc_dec_neighbour(0);
+ else if (mode == MODE_SPECTRUM)
+ inc_dec_spectrum(1);
+ break;
+ case KEY_DOWN:
+ if (mode == MODE_MAIN)
+ tone_inc_dec(0);
+ else if (mode == MODE_SYNC)
+ inc_dec_neighbour(1);
+ else if (mode == MODE_SPECTRUM)
+ inc_dec_spectrum(0);
+ break;
+ case KEY_RIGHT:
+ if (mode == MODE_MAIN || mode == MODE_SPECTRUM)
+ inc_dec_arfcn(1);
+ else if (mode == MODE_SYNC && cursor < 0)
+ inc_dec_ul_arfcn(1);
+ break;
+ case KEY_LEFT:
+ if (mode == MODE_MAIN || mode == MODE_SPECTRUM)
+ inc_dec_arfcn(0);
+ else if (mode == MODE_SYNC && cursor < 0)
+ inc_dec_ul_arfcn(0);
+ break;
+ case KEY_LEFT_SB:
+ if (mode == MODE_MAIN || mode == MODE_SPECTRUM)
+ toggle_dcs_pcs();
+ else if (mode == MODE_ARFCN)
+ enter_arfcn(key_code);
+ else if (mode == MODE_SYNC)
+ exit_sync();
+ else if (mode == MODE_RACH)
+ exit_rach();
+ break;
+ case KEY_RIGHT_SB:
+ if (mode == MODE_MAIN || mode == MODE_SPECTRUM)
+ toggle_up_down();
+ else if (mode == MODE_ARFCN)
+ enter_arfcn(key_code);
+ else if (mode == MODE_SYNC && cursor < 0)
+ toggle_up_down();
+ break;
+ case KEY_OK:
+ if (mode == MODE_MAIN || mode == MODE_SPECTRUM)
+ enter_sync();
+ else if (mode == MODE_SYNC || mode == MODE_RACH)
+ enter_rach();
+ break;
+ case KEY_MENU:
+ hold_max();
+ break;
+ case KEY_POWER:
+ if (mode == MODE_ARFCN)
+ exit_arfcn();
+ else if (mode == MODE_SYNC)
+ exit_sync();
+ else if (mode == MODE_RACH)
+ exit_rach();
+ else if (mode == MODE_SPECTRUM)
+ toggle_spectrum();
+ break;
+ case KEY_STAR:
+ if (mode == MODE_MAIN || mode == MODE_SPECTRUM)
+ toggle_spectrum();
+ break;
+ default:
+ break;
+ }
+
+ key_code = KEY_INV;
+}
+
+static void handle_tone(void)
+{
+ unsigned long elapsed = jiffies - tone_time;
+
+ if (!tone_on) {
+ if (!tone || mode != MODE_MAIN)
+ return;
+ /* wait depending on power level */
+ if (elapsed < (uint8_t)(63-power))
+ return;
+ buzzer_volume(tone);
+ buzzer_note(NOTE(NOTE_C, OCTAVE_5));
+ tone_time = jiffies;
+ tone_on = 1;
+ return;
+ }
+
+ if (elapsed >= TONE_JIFFIES) {
+ tone_on = 0;
+ tone_time = jiffies;
+ buzzer_volume(0);
+ }
+}
+
+/* PM handling */
+
+static void handle_pm(void)
+{
+ /* start power measurement */
+ if (pm_mode == PM_IDLE && (mode == MODE_MAIN || mode == MODE_SPECTRUM)) {
+ struct msgb *msg = l1ctl_msgb_alloc(L1CTL_PM_REQ);
+ struct l1ctl_pm_req *pm;
+ uint16_t a, e;
+
+ pm = (struct l1ctl_pm_req *) msgb_put(msg, sizeof(*pm));
+ pm->type = 1;
+ if (mode == MODE_MAIN) {
+ a = arfcn;
+ if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX)
+ a |= ARFCN_PCS;
+ if (uplink)
+ a |= ARFCN_UPLINK;
+ e = a;
+ pm_mode = PM_SENT;
+ }
+ if (mode == MODE_SPECTRUM) {
+ if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX) {
+ a = PCS_MIN | ARFCN_PCS;
+ e = PCS_MAX | ARFCN_PCS;
+ } else {
+ a = band->min;
+ e = band->max;
+ }
+ pm_mode = PM_RANGE_SENT;
+ }
+ if (uplink) {
+ a |= ARFCN_UPLINK;
+ e |= ARFCN_UPLINK;
+ }
+ pm->range.band_arfcn_from = htons(a);
+ pm->range.band_arfcn_to = htons(e);
+
+ l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+
+ return;
+ }
+
+ if (pm_mode == PM_RESULT) {
+ pm_mode = PM_IDLE;
+ if (pm_count == pm_max) {
+ int i = 0;
+ int sum = 0;
+
+ if (uplink) {
+ /* find max */
+ for (i = 0; i < pm_count; i++) {
+ if (pm_meas[i] > sum)
+ sum = pm_meas[i];
+ }
+ power = sum;
+ } else {
+ for (i = 0; i < pm_count; i++)
+ sum += pm_meas[i];
+ power = sum / pm_count;
+ }
+ if (power > max_power)
+ max_power = power;
+ pm_count = 0;
+ pm_max = (uplink) ? NUM_PM_UL : NUM_PM_DL;
+ if (!tone_on)
+ refresh_display();
+ }
+ return;
+ }
+
+ if (pm_mode == PM_RANGE_RESULT) {
+ pm_mode = PM_IDLE;
+ refresh_display();
+ buzzer_volume(tone);
+ buzzer_note(NOTE(NOTE_C, OCTAVE_5));
+ tone_time = jiffies;
+ tone_on = 1;
+ return;
+ }
+}
+
+/* sync / SI */
+
+static void enter_sync(void)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(L1CTL_FBSB_REQ);
+ struct l1ctl_fbsb_req *req;
+ uint16_t a = arfcn;
+
+ l1s_reset();
+ l1s_reset_hw();
+ pm_count = 0;
+ pm_mode = PM_IDLE;
+
+ req = (struct l1ctl_fbsb_req *) msgb_put(msg, sizeof(*req));
+ if (pcs && arfcn >= PCS_MIN && arfcn <= PCS_MAX)
+ a |= ARFCN_PCS;
+ req->band_arfcn = htons(a);
+ req->timeout = htons(100);
+ /* Threshold when to consider FB_MODE1: 4kHz - 1kHz */
+ req->freq_err_thresh1 = htons(11000 - 1000);
+ /* Threshold when to consider SCH: 1kHz - 200Hz */
+ req->freq_err_thresh2 = htons(1000 - 200);
+ /* not used yet! */
+ req->num_freqerr_avg = 3;
+ req->flags = L1CTL_FBSB_F_FB01SB;
+ req->sync_info_idx = 0;
+ req->ccch_mode = CCCH_MODE_NONE;
+ l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+
+ mode = MODE_SYNC;
+ memset(ul_levels, 0, sizeof(ul_levels));
+ si_new = 0;
+ ul_new = 0;
+ ul_arfcn = arfcn;
+ si_1[2] = 0;
+ si_2[2] = 0;
+ si_2bis[2] = 0;
+ si_2ter[2] = 0;
+ si_3[2] = 0;
+ si_4[2] = 0;
+ mcc = mnc = lac = 0;
+ ccch_conf = -1;
+ memset(freq, 0, sizeof(freq));
+ cursor = 0;
+ nb_num = 0;
+ sync_msg = "trying";
+ refresh_display();
+}
+
+static void exit_sync(void)
+{
+ l1s_reset();
+ l1s_reset_hw();
+ pm_count = 0;
+ pm_mode = PM_IDLE;
+ mode = MODE_MAIN;
+}
+
+int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *_mcc,
+uint16_t *_mnc, uint16_t *_lac)
+{
+ *_mcc = ((lai->digits[0] & 0x0f) << 8)
+ | (lai->digits[0] & 0xf0)
+ | (lai->digits[1] & 0x0f);
+ *_mnc = ((lai->digits[2] & 0x0f) << 8)
+ | (lai->digits[2] & 0xf0)
+ | ((lai->digits[1] & 0xf0) >> 4);
+ *_lac = ntohs(lai->lac);
+
+ return 0;
+}
+
+static void request_ul_levels(uint16_t a)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(L1CTL_NEIGH_PM_REQ);
+ struct l1ctl_neigh_pm_req *pm_req =
+ (struct l1ctl_neigh_pm_req *) msgb_put(msg, sizeof(*pm_req));
+ int i;
+
+ if (pcs && a >= PCS_MIN && a <= PCS_MAX)
+ a |= ARFCN_PCS;
+ if (uplink)
+ a |= ARFCN_UPLINK;
+ pm_req->n = 8;
+ for (i = 0; i < 8; i++) {
+ pm_req->band_arfcn[i] = htons(a);
+ pm_req->tn[i] = i;
+ }
+ l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+}
+
+static void handle_sync(void)
+{
+ struct gsm48_system_information_type_1 *si1;
+ struct gsm48_system_information_type_2 *si2;
+ struct gsm48_system_information_type_2bis *si2bis;
+ struct gsm48_system_information_type_2ter *si2ter;
+ struct gsm48_system_information_type_3 *si3;
+ struct gsm48_system_information_type_4 *si4;
+
+ if (mode != MODE_SYNC)
+ return;
+
+ /* once we synced, we take the result and request UL measurement */
+ if (sync_result) {
+ uint16_t a = ul_arfcn;
+
+ sync_msg = sync_result;
+ sync_result = NULL;
+ refresh_display();
+
+ if (sync_msg[0] != 'o')
+ return;
+
+ request_ul_levels(a);
+
+ return;
+ }
+
+ if (tone_on)
+ return;
+
+ /* no UL result, no SI result */
+ if (!ul_new && !(si_new & 0x100))
+ return;
+
+ /* new UL result */
+ if (ul_new) {
+ ul_new = 0;
+ if (cursor < 0)
+ refresh_display();
+ return;
+ }
+
+ /* decode si */
+ switch (si_new & 0xff) {
+ case GSM48_MT_RR_SYSINFO_1:
+ si1 = (struct gsm48_system_information_type_1 *)si_1;
+ gsm48_decode_freq_list(freq, si1->cell_channel_description,
+ sizeof(si1->cell_channel_description), 0xce,
+ FREQ_TYPE_SERV);
+ break;
+ case GSM48_MT_RR_SYSINFO_2:
+ si2 = (struct gsm48_system_information_type_2 *)si_2;
+ gsm48_decode_freq_list(freq, si2->bcch_frequency_list,
+ sizeof(si2->bcch_frequency_list), 0xce,
+ FREQ_TYPE_NCELL_2);
+ break;
+ case GSM48_MT_RR_SYSINFO_2bis:
+ si2bis = (struct gsm48_system_information_type_2bis *)si_2bis;
+ gsm48_decode_freq_list(freq, si2bis->bcch_frequency_list,
+ sizeof(si2bis->bcch_frequency_list), 0xce,
+ FREQ_TYPE_NCELL_2bis);
+ break;
+ case GSM48_MT_RR_SYSINFO_2ter:
+ si2ter = (struct gsm48_system_information_type_2ter *)si_2ter;
+ gsm48_decode_freq_list(freq, si2ter->ext_bcch_frequency_list,
+ sizeof(si2ter->ext_bcch_frequency_list), 0x8e,
+ FREQ_TYPE_NCELL_2ter);
+ break;
+ case GSM48_MT_RR_SYSINFO_3:
+ si3 = (struct gsm48_system_information_type_3 *)si_3;
+ gsm48_decode_lai(&si3->lai, &mcc, &mnc, &lac);
+ cell_id = ntohs(si3->cell_identity);
+ if (ccch_conf < 0) {
+ struct msgb *msg =
+ l1ctl_msgb_alloc(L1CTL_CCCH_MODE_REQ);
+ struct l1ctl_ccch_mode_req *req =
+ (struct l1ctl_ccch_mode_req *)
+ msgb_put(msg, sizeof(*req));
+
+ ccch_conf = si3->control_channel_desc.ccch_conf;
+ req->ccch_mode = (ccch_conf == 1)
+ ? CCCH_MODE_COMBINED
+ : CCCH_MODE_NON_COMBINED;
+ printf("ccch_mode=%d\n", ccch_conf);
+
+ l1a_l23_rx(SC_DLCI_L1A_L23, msg);
+ }
+ break;
+ case GSM48_MT_RR_SYSINFO_4:
+ si4 = (struct gsm48_system_information_type_4 *)si_4;
+ gsm48_decode_lai(&si4->lai, &mcc, &mnc, &lac);
+ break;
+ }
+
+ if (cursor >= 0)
+ refresh_display();
+
+ /* tone depends on successfully received BCCH */
+ buzzer_volume(tone);
+ tone_time = jiffies;
+ tone_on = 1;
+ if ((si_new & 0xff) == 0xff)
+ buzzer_note(NOTE(NOTE_C, OCTAVE_2));
+ else
+ buzzer_note(NOTE(NOTE_C, OCTAVE_5));
+ si_new = 0;
+}
+
+static void enter_rach(void)
+{
+ if (ccch_conf < 0)
+ return;
+
+ if (rach)
+ return;
+
+#ifndef CONFIG_TX_ENABLE
+ assign = ASSIGN_NO_TX;
+ mode = MODE_RACH;
+ /* display refresh is done by rach handler */
+#else
+ struct msgb *msg1 = l1ctl_msgb_alloc(L1CTL_NEIGH_PM_REQ);
+ struct msgb *msg2 = l1ctl_msgb_alloc(L1CTL_RACH_REQ);
+ struct l1ctl_neigh_pm_req *pm_req = (struct l1ctl_neigh_pm_req *)
+ msgb_put(msg1, sizeof(*pm_req));
+ struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)
+ msgb_put(msg2, sizeof(*ul));;
+ struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *)
+ msgb_put(msg2, sizeof(*rach_req));
+
+ l1s.tx_power = 0;
+
+ pm_req->n = 0; /* disable */
+
+ rach_ra = 0x00;
+ rach_req->ra = rach_ra;
+ rach_req->offset = 0;
+ rach_req->combined = (ccch_conf == 1);
+
+ l1a_l23_rx(SC_DLCI_L1A_L23, msg1);
+ l1a_l23_rx(SC_DLCI_L1A_L23, msg2);
+ rach = 1;
+ rach_when = jiffies;
+ assign = ASSIGN_NONE;
+ mode = MODE_RACH;
+ refresh_display();
+#endif
+
+}
+
+static void exit_rach(void)
+{
+ rach = 0;
+
+ request_ul_levels(ul_arfcn);
+
+ mode = MODE_SYNC;
+ refresh_display();
+}
+
+static void handle_assign(void)
+{
+ if (mode != MODE_RACH)
+ return;
+
+ if (assign == ASSIGN_NONE) {
+ unsigned long elapsed = jiffies - rach_when;
+
+ if (!rach)
+ return;
+ if (elapsed < HZ * 2)
+ return;
+ assign = ASSIGN_TIMEOUT;
+ rach = 0;
+ }
+
+ refresh_display();
+ assign = ASSIGN_NONE;
+}
+
+/* Main Program */
+const char *hr = "======================================================================\n";
+
+/* match request reference agains request history */
+static int gsm48_match_ra(struct gsm48_req_ref *ref)
+{
+ uint8_t ia_t1, ia_t2, ia_t3;
+ uint8_t cr_t1, cr_t2, cr_t3;
+
+ if (rach && ref->ra == rach_ra) {
+ ia_t1 = ref->t1;
+ ia_t2 = ref->t2;
+ ia_t3 = (ref->t3_high << 3) | ref->t3_low;
+ ref = &rach_ref;
+ cr_t1 = ref->t1;
+ cr_t2 = ref->t2;
+ cr_t3 = (ref->t3_high << 3) | ref->t3_low;
+ if (ia_t1 == cr_t1 && ia_t2 == cr_t2 && ia_t3 == cr_t3)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* note: called from IRQ context */
+static void rx_imm_ass(struct msgb *msg)
+{
+ struct gsm48_imm_ass *ia = msgb_l3(msg);
+
+ if (gsm48_match_ra(&ia->req_ref)) {
+ assign = ASSIGN_RESULT;
+ ta = ia->timing_advance;
+ rach = 0;
+ }
+}
+
+/* note: called from IRQ context */
+static void rx_imm_ass_ext(struct msgb *msg)
+{
+ struct gsm48_imm_ass_ext *ia = msgb_l3(msg);
+
+ if (gsm48_match_ra(&ia->req_ref1)) {
+ assign = ASSIGN_RESULT;
+ ta = ia->timing_advance1;
+ rach = 0;
+ }
+ if (gsm48_match_ra(&ia->req_ref2)) {
+ assign = ASSIGN_RESULT;
+ ta = ia->timing_advance2;
+ rach = 0;
+ }
+}
+
+/* note: called from IRQ context */
+static void rx_imm_ass_rej(struct msgb *msg)
+{
+ struct gsm48_imm_ass_rej *ia = msgb_l3(msg);
+ struct gsm48_req_ref *req_ref;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ /* request reference */
+ req_ref = (struct gsm48_req_ref *)
+ (((uint8_t *)&ia->req_ref1) + i * 4);
+ if (gsm48_match_ra(req_ref)) {
+ assign = ASSIGN_REJECT;
+ rach = 0;
+ }
+ }
+}
+
+/* note: called from IRQ context */
+static void rx_pch_agch(struct msgb *msg)
+{
+ struct gsm48_system_information_type_header *sih;
+
+ /* store SI */
+ sih = msgb_l3(msg);
+ switch (sih->system_information) {
+ case GSM48_MT_RR_IMM_ASS:
+ rx_imm_ass(msg);
+ break;
+ case GSM48_MT_RR_IMM_ASS_EXT:
+ rx_imm_ass_ext(msg);
+ break;
+ case GSM48_MT_RR_IMM_ASS_REJ:
+ rx_imm_ass_rej(msg);
+ break;
+ }
+}
+
+/* note: called from IRQ context */
+static void rx_bcch(struct msgb *msg)
+{
+ struct gsm48_system_information_type_header *sih;
+
+ /* store SI */
+ sih = msgb_l3(msg);
+ switch (sih->system_information) {
+ case GSM48_MT_RR_SYSINFO_1:
+ memcpy(si_1, msgb_l3(msg), msgb_l3len(msg));
+ break;
+ case GSM48_MT_RR_SYSINFO_2:
+ memcpy(si_2, msgb_l3(msg), msgb_l3len(msg));
+ break;
+ case GSM48_MT_RR_SYSINFO_2bis:
+ memcpy(si_2bis, msgb_l3(msg), msgb_l3len(msg));
+ break;
+ case GSM48_MT_RR_SYSINFO_2ter:
+ memcpy(si_2ter, msgb_l3(msg), msgb_l3len(msg));
+ break;
+ case GSM48_MT_RR_SYSINFO_3:
+ memcpy(si_3, msgb_l3(msg), msgb_l3len(msg));
+ break;
+ case GSM48_MT_RR_SYSINFO_4:
+ memcpy(si_4, msgb_l3(msg), msgb_l3len(msg));
+ break;
+ }
+ si_new = sih->system_information | 0x100;
+}
+
+/* note: called from IRQ context */
+static void l1a_l23_tx(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->l1h;
+ struct l1ctl_pm_conf *pmr;
+ struct l1ctl_info_dl *dl;
+ struct l1ctl_fbsb_conf *sb;
+ uint8_t chan_type, chan_ts, chan_ss;
+ struct l1ctl_neigh_pm_ind *pm_ind;
+ struct gsm_time tm;
+
+ switch (l1h->msg_type) {
+ case L1CTL_PM_CONF:
+ if (pm_mode == PM_SENT) {
+ pmr = (struct l1ctl_pm_conf *) l1h->data;
+ pm_meas[pm_count] = pmr->pm[0];
+ pm_count++;
+ pm_mode = PM_RESULT;
+ }
+ if (pm_mode == PM_RANGE_SENT) {
+ for (pmr = (struct l1ctl_pm_conf *) l1h->data;
+ (uint8_t *) pmr < msg->tail; pmr++) {
+ if (!max || pm_spectrum[ntohs(pmr->band_arfcn) & 1023] < pmr->pm[0])
+ pm_spectrum[ntohs(pmr->band_arfcn) & 1023] = pmr->pm[0];
+ }
+ if ((l1h->flags & L1CTL_F_DONE))
+ pm_mode = PM_RANGE_RESULT;
+ }
+ l1s.tpu_offset_correction += 5000 / NUM_PM_UL;
+ break;
+ case L1CTL_FBSB_CONF:
+ dl = (struct l1ctl_info_dl *) l1h->data;
+ sb = (struct l1ctl_fbsb_conf *) dl->payload;
+ if (sb->result == 0)
+ sync_result = "ok";
+ else
+ sync_result = "error";
+ bsic = sb->bsic;
+ break;
+ case L1CTL_DATA_IND:
+ dl = (struct l1ctl_info_dl *) l1h->data;
+ msg->l2h = dl->payload;
+ rsl_dec_chan_nr(dl->chan_nr, &chan_type, &chan_ss, &chan_ts);
+
+ power = dl->rx_level;
+ if (dl->fire_crc >= 2) {
+ if (chan_type == RSL_CHAN_BCCH)
+ si_new = 0x1ff; /* error frame indication */
+ break; /* free, but don't send to sercom */
+ }
+
+ switch (chan_type) {
+ case RSL_CHAN_BCCH:
+ msg->l3h = msg->l2h;
+ rx_bcch(msg);
+ break;
+ case RSL_CHAN_PCH_AGCH:
+ msg->l3h = msg->l2h;
+ rx_pch_agch(msg);
+ break;
+ }
+ sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
+ return; /* msg is freed by sercom */
+ case L1CTL_NEIGH_PM_IND:
+ for (pm_ind = (struct l1ctl_neigh_pm_ind *) l1h->data;
+ (uint8_t *) pm_ind < msg->tail; pm_ind++) {
+ ul_levels[pm_ind->tn] = pm_ind->pm[0];
+ /* hold max only, if max enabled and level is lower */
+ if (!max || ul_levels[pm_ind->tn] > ul_max[pm_ind->tn])
+ ul_max[pm_ind->tn] = ul_levels[pm_ind->tn];
+ if (pm_ind->tn == 7)
+ ul_new = 1;
+ }
+ break;
+ case L1CTL_RACH_CONF:
+ dl = (struct l1ctl_info_dl *) l1h->data;
+ gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr));
+ rach_ref.t1 = tm.t1;
+ rach_ref.t2 = tm.t2;
+ rach_ref.t3_low = tm.t3 & 0x7;
+ rach_ref.t3_high = tm.t3 >> 3;
+ break;
+ }
+
+ msgb_free(msg);
+
+}
+
+static void console_rx_cb(uint8_t dlci, struct msgb *msg)
+{
+ if (dlci != SC_DLCI_CONSOLE) {
+ printf("Message for unknown DLCI %u\n", dlci);
+ return;
+ }
+
+ printf("Message on console DLCI: '%s'\n", msg->data);
+ msgb_free(msg);
+}
+
+static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
+{
+ int i;
+ printf("l1a_l23_rx_cb (DLCI %d): ", dlci);
+ for (i = 0; i < msg->len; i++)
+ printf("%02x ", msg->data[i]);
+ puts("\n");
+}
+
+static void key_handler(enum key_codes code, enum key_states state)
+{
+ if (state != PRESSED) {
+ key_pressed = 0;
+ return;
+ }
+ /* key repeat */
+ if (!key_pressed) {
+ key_pressed = 1;
+ key_pressed_when = jiffies;
+ key_pressed_code = code;
+ key_pressed_delay = HZ * 6 / 10;
+ }
+
+ key_code = code;
+}
+
+int main(void)
+{
+ board_init();
+
+ puts("\n\nOsmocomBB Monitor Tool (revision " GIT_REVISION ")\n");
+ puts(hr);
+
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ /* Dump clock config before PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ keypad_set_handler(&key_handler);
+
+ /* Dump clock config after PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ sercomm_register_rx_cb(SC_DLCI_CONSOLE, console_rx_cb);
+ sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
+
+ layer1_init();
+ l1a_l23_tx_cb = l1a_l23_tx;
+
+// display_unset_attr(DISP_ATTR_INVERT);
+
+ tpu_frame_irq_en(1, 1);
+
+ buzzer_mode_pwt(1);
+ buzzer_volume(0);
+
+ memset(pm_spectrum, 0, sizeof(pm_spectrum));
+ memset(ul_max, 0, sizeof(ul_max));
+
+ /* inc 0 to 1 and refresh */
+ inc_dec_arfcn(1);
+
+ while (1) {
+ l1a_compl_execute();
+ osmo_timers_update();
+ handle_key_code();
+ l1a_l23_handler();
+ handle_pm();
+ handle_sync();
+ handle_assign();
+ handle_tone();
+ }
+
+ /* NOT REACHED */
+
+ twl3025_power_off();
+}
+
diff --git a/src/target/firmware/apps/simtest/main.c b/src/target/firmware/apps/simtest/main.c
new file mode 100755
index 00000000..8e089d32
--- /dev/null
+++ b/src/target/firmware/apps/simtest/main.c
@@ -0,0 +1,362 @@
+/* SIM test application */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <delay.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/irq.h>
+#include <calypso/misc.h>
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <calypso/sim.h>
+
+#define DEBUG
+
+/* Dump bytes in hex on the console */
+static void myHexdump(uint8_t *data, int len)
+{
+ int i;
+
+ for(i=0;i<len;i++)
+ printf("%02x ",data[i]);
+
+ printf("(%i bytes)\n", len);
+
+ return;
+}
+
+/* SIM instructions
+ All instructions a standard sim card must feature: */
+#define SIM_CLASS 0xA0 /* Class that contains the following instructions */
+#define SIM_SELECT 0xA4 /* Select a file on the card */
+#define SIM_STATUS 0xF2 /* Get the status of the currently selected file */
+#define SIM_READ_BINARY 0xB0 /* Read file in binary mode */
+#define SIM_UPDATE_BINARY 0xD6 /* Write file in binary mode */
+#define SIM_READ_RECORD 0xB2 /* Read record of a record based file */
+#define SIM_UPDATE_RECORD 0xDC /* Write record of a record based file */
+#define SIM_SEEK 0xA2 /* Seek in a record based file */
+#define SIM_INCREASE 0x32 /* Increase a record in a record based file */
+#define SIM_VERIFY_CHV 0x20 /* Authenticate with card (enter pin) */
+#define SIM_CHANGE_CHV 0x24 /* Change pin */
+#define SIM_DISABLE_CHV 0x26 /* Disable pin so that no authentication is needed anymore */
+#define SIM_ENABLE_CHV 0x28 /* Enable pin, authentication is now needed again */
+#define SIM_UNBLOCK_CHV 0x2C /* Unblock pin when it is blocked by entering a wrong pin three times */
+#define SIM_INVALIDATE 0x04 /* Invalidate the current elementry file (file in a subdirectory) */
+#define SIM_REHABILITATE 0x44 /* Rehabilitate the current elementry file (file in a subdirectory) */
+#define SIM_RUN_GSM_ALGORITHM 0x88 /* Run the GSM A3 authentication algorithm in the card */
+#define SIM_SLEEP 0xFA /* Sleep command (only used in Phase 1 GSM) */
+#define SIM_GET_RESPONSE 0xC0 /* Get the response of a command from the card */
+
+/* File identifiers (filenames)
+ The file identifiers are the standardized file identifiers mentioned in the
+ GSM-11-11 specification. */
+#define SIM_MF 0x3F00
+#define SIM_EF_ICCID 0x2FE2
+#define SIM_DF_TELECOM 0x7F10
+#define SIM_EF_ADN 0x6F3A
+#define SIM_EF_FDN 0x6F3B
+#define SIM_EF_SMS 0x6F3C
+#define SIM_EF_CCP 0x6F3D
+#define SIM_EF_MSISDN 0x6F40
+#define SIM_EF_SMSP 0x6F42
+#define SIM_EF_SMSS 0x6F43
+#define SIM_EF_LND 0x6F44
+#define SIM_EF_EXT1 0x6F4A
+#define SIM_EF_EXT2 0x6F4B
+#define SIM_DF_GSM 0x7F20
+#define SIM_EF_LP 0x6F05
+#define SIM_EF_IMSI 0x6F07
+#define SIM_EF_KC 0x6F20
+#define SIM_EF_PLMNsel 0x6F30
+#define SIM_EF_HPLMN 0x6F31
+#define SIM_EF_ACMmax 0x6F37
+#define SIM_EF_SST 0x6F38
+#define SIM_EF_ACM 0x6F39
+#define SIM_EF_GID1 0x6F3E
+#define SIM_EF_GID2 0x6F3F
+#define SIM_EF_PUCT 0x6F41
+#define SIM_EF_CBMI 0x6F45
+#define SIM_EF_SPN 0x6F46
+#define SIM_EF_BCCH 0x6F74
+#define SIM_EF_ACC 0x6F78
+#define SIM_EF_FPLMN 0x6F7B
+#define SIM_EF_LOCI 0x6F7E
+#define SIM_EF_AD 0x6FAD
+#define SIM_EF_PHASE 0x6FAE
+
+/* Select a file on the card */
+uint16_t sim_select(uint16_t fid)
+{
+ uint8_t txBuffer[2];
+ uint8_t status_word[2];
+
+ txBuffer[1] = (uint8_t) fid;
+ txBuffer[0] = (uint8_t) (fid >> 8);
+
+ if(calypso_sim_transceive(SIM_CLASS, SIM_SELECT, 0x00, 0x00, 0x02,
+ txBuffer, status_word, SIM_APDU_PUT) != 0)
+ return 0xFFFF;
+
+ return (status_word[0] << 8) | status_word[1];
+}
+
+/* Get the status of the currently selected file */
+uint16_t sim_status(void)
+{
+ uint8_t status_word[2];
+
+ if(calypso_sim_transceive(SIM_CLASS, SIM_STATUS, 0x00, 0x00, 0x00, 0,
+ status_word, SIM_APDU_PUT) != 0)
+ return 0xFFFF;
+
+ return (status_word[0] << 8) | status_word[1];
+}
+
+/* Read file in binary mode */
+uint16_t sim_readbinary(uint8_t offset_high, uint8_t offset_low, uint8_t length, uint8_t *data)
+{
+ uint8_t status_word[2];
+ if(calypso_sim_transceive(SIM_CLASS, SIM_READ_BINARY, offset_high,
+ offset_low, length, data ,status_word,
+ SIM_APDU_GET) != 0)
+ return 0xFFFF;
+
+ return (status_word[0] << 8) | status_word[1];
+}
+
+uint16_t sim_verify(char *pin)
+{
+ uint8_t txBuffer[8];
+ uint8_t status_word[2];
+
+ memset(txBuffer, 0xFF, 8);
+ memcpy(txBuffer, pin, strlen(pin));
+
+ if(calypso_sim_transceive(SIM_CLASS, SIM_VERIFY_CHV, 0x00, 0x01, 0x08, txBuffer,status_word, SIM_APDU_PUT) != 0)
+ return 0xFFFF;
+
+ return (status_word[0] << 8) | status_word[1];
+}
+
+uint16_t sim_run_gsm_algorith(uint8_t *data)
+{
+ uint8_t status_word[2];
+
+ if(calypso_sim_transceive(SIM_CLASS, SIM_RUN_GSM_ALGORITHM, 0x00, 0x00, 0x10, data, status_word, SIM_APDU_PUT) != 0)
+ return 0xFFFF;
+
+ printf(" ==> Status word: %x\n", (status_word[0] << 8) | status_word[1]);
+
+ if(status_word[0] != 0x9F || status_word[1] != 0x0C)
+ return (status_word[0] << 8) | status_word[1];
+
+ /* GET RESPONSE */
+
+ if(calypso_sim_transceive(SIM_CLASS, SIM_GET_RESPONSE, 0, 0, 0x0C, data ,status_word, SIM_APDU_GET) != 0)
+ return 0xFFFF;
+
+ return (status_word[0] << 8) | status_word[1];
+}
+
+
+/* FIXME: We need proper calibrated delay loops at some point! */
+void delay_us(unsigned int us)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < us*4; i++) { i; }
+}
+
+void delay_ms(unsigned int ms)
+{
+ volatile unsigned int i;
+ for (i= 0; i < ms*1300; i++) { i; }
+}
+
+/* Execute my (dexter's) personal test */
+void do_sim_test(void)
+{
+ uint8_t testBuffer[20];
+ uint8_t testtxBuffer[20];
+
+ uint8_t testDataBody[257];
+ uint8_t testStatusWord[2];
+ int recivedChars;
+ int i;
+
+ uint8_t atr[20];
+ uint8_t atrLength = 0;
+
+ memset(atr,0,sizeof(atr));
+
+
+
+ uint8_t buffer[20];
+
+
+ memset(testtxBuffer,0,sizeof(testtxBuffer));
+
+ puts("----------------SIMTEST----8<-----------------\n");
+
+ /* Initialize Sim-Controller driver */
+ puts("Initializing driver:\n");
+ calypso_sim_init(NULL);
+
+ /* Power up sim and display ATR */
+ puts("Power up simcard:\n");
+ memset(atr,0,sizeof(atr));
+ atrLength = calypso_sim_powerup(atr);
+ myHexdump(atr,atrLength);
+
+ /* Reset sim and display ATR */
+ puts("Reset simcard:\n");
+ memset(atr,0,sizeof(atr));
+ atrLength = calypso_sim_reset(atr);
+ myHexdump(atr,atrLength);
+
+
+
+ testDataBody[0] = 0x3F;
+ testDataBody[1] = 0x00;
+ calypso_sim_transceive(0xA0, 0xA4, 0x00, 0x00, 0x02, testDataBody,0, SIM_APDU_PUT);
+ calypso_sim_transceive(0xA0, 0xC0, 0x00, 0x00, 0x0f, testDataBody,0, SIM_APDU_GET);
+ myHexdump(testDataBody,0x0F);
+
+ puts("Test Phase 1: Testing bare sim commands...\n");
+
+ puts(" * Testing SELECT: Selecting MF\n");
+ printf(" ==> Status word: %x\n", sim_select(SIM_MF));
+
+ puts(" * Testing SELECT: Selecting DF_GSM\n");
+ printf(" ==> Status word: %x\n", sim_select(SIM_DF_GSM));
+
+ puts(" * Testing PIN VERIFY\n");
+ printf(" ==> Status word: %x\n", sim_verify("1234"));
+
+ puts(" * Testing SELECT: Selecting EF_IMSI\n");
+ printf(" ==> Status word: %x\n", sim_select(SIM_EF_IMSI));
+
+ puts(" * Testing STATUS:\n");
+ printf(" ==> Status word: %x\n", sim_status());
+
+ memset(buffer,0,sizeof(buffer));
+ puts(" * Testing READ BINARY:\n");
+ printf(" ==> Status word: %x\n", sim_readbinary(0,0,9,buffer));
+ printf(" Data: ");
+ myHexdump(buffer,9);
+
+ memset(buffer,0,sizeof(buffer));
+ memcpy(buffer,"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff",16);
+ puts(" * Testing RUN GSM ALGORITHM\n");
+ printf(" ==> Status word: %x\n", sim_run_gsm_algorith(buffer));
+ printf(" Result: ");
+ myHexdump(buffer,12);
+
+ delay_ms(5000);
+
+ calypso_sim_powerdown();
+
+ puts("------------END SIMTEST----8<-----------------\n");
+}
+
+/* Main Program */
+const char *hr = "======================================================================\n";
+
+void key_handler(enum key_codes code, enum key_states state);
+
+static void *console_rx_cb(uint8_t dlci, struct msgb *msg)
+{
+ if (dlci != SC_DLCI_CONSOLE) {
+ printf("Message for unknown DLCI %u\n", dlci);
+ return;
+ }
+
+ printf("Message on console DLCI: '%s'\n", msg->data);
+ msgb_free(msg);
+}
+
+int main(void)
+{
+ board_init();
+
+ puts("\n\nOsmocomBB SIM Test (revision " GIT_REVISION ")\n");
+ puts(hr);
+
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ /* Dump clock config before PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ keypad_set_handler(&key_handler);
+
+ /* Dump clock config after PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ /* Dump all memory */
+ //dump_mem();
+#if 0
+ /* Dump Bootloader */
+ memdump_range((void *)0x00000000, 0x2000);
+ puts(hr);
+#endif
+
+ sercomm_register_rx_cb(SC_DLCI_CONSOLE, console_rx_cb);
+
+ do_sim_test();
+
+ /* beyond this point we only react to interrupts */
+ puts("entering interrupt loop\n");
+ while (1) {
+ }
+
+ twl3025_power_off();
+ while (1) {}
+}
+
+void key_handler(enum key_codes code, enum key_states state)
+{
+ if (state != PRESSED)
+ return;
+
+ switch (code) {
+ default:
+ break;
+ }
+}
diff --git a/src/target/firmware/battery/compal_e88.c b/src/target/firmware/battery/compal_e88.c
new file mode 100644
index 00000000..609d4063
--- /dev/null
+++ b/src/target/firmware/battery/compal_e88.c
@@ -0,0 +1,384 @@
+/* Battery management for compal_e88 */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/*
+ * ___C123 (compal e88) very simplified diagram of charging circuitry___
+ *
+ * ICTL
+ * |
+ * v
+ * Charger -> OVP -------> P-Mosfet --->[0.15 Ohm]---> Battery
+ * (NCP345, | | |
+ * 6.85V) v v v
+ * VCHG VCCS VBAT &
+ * VBATS
+ *
+ * Inputs to IOTA:
+ * VCHG: senses voltage on the charger input
+ * VCSS/VBATS: to difference amplifier, to measure charge current
+ * VBAT: senses voltage on the battery terminal
+ * Outputs from IOTA:
+ * ICTL: Control signal for the switching mosfet
+ *
+ */
+
+#include <battery/battery.h>
+#include <battery/compal_e88.h>
+
+#include <stdint.h>
+#include <abb/twl3025.h>
+#include <comm/timer.h>
+#include <stdio.h>
+
+/* ADC calibration, scale is LSB/uV or LSB/uA, physical unit is mV or mA */
+#define ADC_TO_PHYSICAL(adc,scale) (((adc)*(scale)+500)/1000)
+#define PHYSICAL_TO_ADC(phy,scale) (((phy)*1000+(scale)/2)/(scale))
+
+/* conversion factors for internal IOTA battery charging/sensing circuitry */
+#define VREF_LSB_uV 1709 /* VREF = 1.75V --> 1.709 mV/LSB */
+#define VBAT_LSB_uV 6836 /* VBAT = 7.0 V FS --> 6.836 mV/LSB */
+#define VCHG_LSB_uV 8545 /* VCHG = 8.75V FS --> 8.545 mV/LSB */
+#define ICHG_LSB_uA 854 /* ICHG = 875mA FS --> 0.854 mA/LSB */
+
+/* battery is considered full/empty at these thresholds... */
+#define VBAT_full PHYSICAL_TO_ADC(4000,VBAT_LSB_uV)
+#define VBAT_empty PHYSICAL_TO_ADC(3200,VBAT_LSB_uV)
+
+/* we declare overvoltage at this point... */
+#define VBAT_fail PHYSICAL_TO_ADC(4250,VBAT_LSB_uV)
+
+/* DAC to ADC offsets in CC mode with my C123
+ IMEI 358317015976471, P329431014
+
+ I/mA DAC ADC
+ ----------------
+ 100 117 108
+ 150 176 168
+ 200 234 227
+ 250 293 291
+ 300 351 349
+ 350 410 410
+*/
+
+#define CHGDAC_GAIN 967 /* times 0.001 */
+#define CHGDAC_OFFS 13
+
+/* convert ADC reading to DAC value, according to calibration values
+ given above */
+#define CHGDAC_ADJ(x) (CHGDAC_GAIN*(x)/1000+CHGDAC_OFFS)
+
+/* charging current in DAC LSBs, same ref. and # of bits, but keep
+ the correction specified above in mind! */
+
+#define ICHG_set CHGDAC_ADJ(PHYSICAL_TO_ADC(200,ICHG_LSB_uA))
+#define VCHG_set CHGDAC_ADJ(VBAT_full)
+
+struct battery_info battery_info; /* global battery info */
+uint16_t bat_compal_e88_madc[MADC_NUM_CHANNELS]; /* MADC measurements */
+
+static const int BATTERY_TIMER_DELAY=5000; /* 5000ms for control loop */
+static const int ADC_TIMER_DELAY=100; /* 100ms for ADC conversion */
+
+/* thermistor sense current, turn it up to eleven! */
+#define TH_SENS (THSENS0|THSENS1|THSENS2|THEN)
+#define BATTERY_ALL_SENSE (TH_SENS|MESBAT|TYPEN)
+
+/*
+ * charger modes state machine
+ *
+ * +------------------+-------------------+
+ * | | | lost AC power
+ * | ^ ^
+ * V on AC power | @VBAT_full |
+ * +-----+ +------------+ -----> +------------+
+ * | OFF | -----> | CONST_CURR | | CONST_VOLT |
+ * +-----+ +------------+ +------------+
+ * ^ ^ | |
+ * | /failure v v failure
+ * +---------+ / gone | | condition
+ * | FAILURE | <----------+-------------------+
+ * +---------+
+ *
+ * Failure modes currently detected:
+ * + high battery voltage
+ * Failure modes TODO:
+ * + high battery temperature
+ */
+enum bat_compal_e88_chg_state {
+ CHARG_OFF,
+ CHARG_CONST_CURR,
+ CHARG_CONST_VOLT,
+ CHARG_FAIL
+};
+static enum bat_compal_e88_chg_state bat_compal_e88_chg_state;
+
+static const char *bat_compal_e88_chg_state_names[]={
+ "Off",
+ "Constant Current",
+ "Constant Voltage",
+ "Battery Failure"
+};
+
+static void
+bat_compal_e88_goto_state(enum bat_compal_e88_chg_state newstate){
+
+ if(bat_compal_e88_chg_state == newstate) /* already there? */
+ return;
+
+ printf("\033[34;1mCHARGER: %s --> %s.\033[0m\n",
+ bat_compal_e88_chg_state_names[bat_compal_e88_chg_state],
+ bat_compal_e88_chg_state_names[newstate]);
+
+ /* update user visible flags, set registers */
+ switch(newstate){
+ case CHARG_CONST_CURR:
+ battery_info.flags &= ~BATTERY_FAILURE;
+ battery_info.flags |= (BATTERY_CHG_ENABLED|
+ BATTERY_CHARGING);
+ twl3025_reg_write(BCICTL2,0);
+ twl3025_reg_write(CHGREG,0);
+ twl3025_reg_write(BCICTL2,CHEN|LEDC|CHIV);
+ twl3025_reg_write(CHGREG,ICHG_set);
+
+ break;
+
+ case CHARG_CONST_VOLT:
+ battery_info.flags &= ~( BATTERY_CHARGING |
+ BATTERY_FAILURE );
+ battery_info.flags |= BATTERY_CHG_ENABLED;
+ twl3025_reg_write(BCICTL2,0);
+ twl3025_reg_write(CHGREG,0);
+ twl3025_reg_write(BCICTL2,CHEN|LEDC);
+ twl3025_reg_write(CHGREG,VCHG_set);
+ break;
+
+ case CHARG_FAIL:
+ case CHARG_OFF:
+ default:
+ battery_info.flags &= ~( BATTERY_CHG_ENABLED |
+ BATTERY_CHARGING | BATTERY_FAILURE );
+ twl3025_reg_write(BCICTL2,0); /* turn off charger */
+ twl3025_reg_write(CHGREG,0);
+ break;
+ }
+
+ printf("BCICTL2 is 0x%03x, CHGREG=%d\n",
+ twl3025_reg_read(BCICTL2),
+ twl3025_reg_read(CHGREG));
+
+ bat_compal_e88_chg_state = newstate;
+}
+
+static void
+bat_compal_e88_chg_control(){
+ /* with AC power disconnected, always go to off state */
+ if(!(battery_info.flags & BATTERY_CHG_CONNECTED)){
+ bat_compal_e88_goto_state(CHARG_OFF);
+ return;
+ }
+
+ /* if failure condition is detected, always goto failure state */
+ if(bat_compal_e88_madc[MADC_VBAT] > VBAT_fail){
+ bat_compal_e88_goto_state(CHARG_FAIL);
+ return;
+ }
+
+ /* now AC power is present and battery is not over failure
+ thresholds */
+ switch(bat_compal_e88_chg_state){
+ case CHARG_OFF:
+ if(bat_compal_e88_madc[MADC_VBAT] >= VBAT_full)
+ bat_compal_e88_goto_state(CHARG_CONST_VOLT);
+ else
+ bat_compal_e88_goto_state(CHARG_CONST_CURR);
+ break;
+ case CHARG_CONST_CURR:
+ if(bat_compal_e88_madc[MADC_VBAT] >= VBAT_full)
+ bat_compal_e88_goto_state(CHARG_CONST_VOLT);
+ break;
+ case CHARG_CONST_VOLT:
+ break;
+ default:
+ case CHARG_FAIL:
+ if(bat_compal_e88_madc[MADC_VBAT] < VBAT_full)
+ bat_compal_e88_goto_state(CHARG_CONST_CURR);
+ break;
+ }
+}
+
+/*
+ * Charging voltage connection - state machine, remembers
+ * state in battery_info.flags.
+ *
+ * VCHG > VCHG_thr_on
+ * +-----------------+ ------------------> +---------------+
+ * | ! CHG_CONNECTED | | CHG_CONNECTED |
+ * +-----------------+ <------------------ +---------------+
+ * VCHG < VCHG_thr_off
+ */
+static void
+bat_compal_e88_chk_ac_presence(){
+ int vrpcsts = twl3025_reg_read(VRPCSTS);
+
+ /* check for presence of charging voltage */
+ if(!(battery_info.flags & BATTERY_CHG_CONNECTED)){
+ if(vrpcsts & CHGPRES){
+ puts("\033[34;1mCHARGER: external voltage connected!\033[0m\n");
+ battery_info.flags |= BATTERY_CHG_CONNECTED;
+
+ /* always keep ADC, voltage dividers and bias voltages on */
+ twl3025_unit_enable(TWL3025_UNIT_MAD,1);
+ twl3025_reg_write(BCICTL1,BATTERY_ALL_SENSE);
+ }
+ } else {
+ if(!(vrpcsts & CHGPRES)){
+ /* we'll only run ADC on demand */
+ twl3025_unit_enable(TWL3025_UNIT_MAD,0);
+ twl3025_reg_write(BCICTL1,0);
+
+ battery_info.flags &= ~ BATTERY_CHG_CONNECTED;
+ puts("\033[34;1mCHARGER: external voltage disconnected!\033[0m\n");
+ }
+ }
+}
+
+/* ---- update voltages visible to the user ---- */
+static void
+bat_compal_e88_upd_measurements(){
+ int adc,i;
+
+ battery_info.charger_volt_mV=
+ ADC_TO_PHYSICAL(bat_compal_e88_madc[MADC_VCHG],VCHG_LSB_uV);
+ battery_info.bat_volt_mV=
+ ADC_TO_PHYSICAL(bat_compal_e88_madc[MADC_VBAT],VBAT_LSB_uV);
+ battery_info.bat_chg_curr_mA=
+ ADC_TO_PHYSICAL(bat_compal_e88_madc[MADC_ICHG],ICHG_LSB_uA);
+
+ adc = bat_compal_e88_madc[MADC_VBAT];
+ if(adc <= VBAT_empty){ /* battery 0..100% */
+ battery_info.battery_percent = 0;
+ } else if (adc >= VBAT_full){
+ battery_info.battery_percent = 100;
+ } else {
+ battery_info.battery_percent =
+ (50+100*(adc-VBAT_empty))/(VBAT_full-VBAT_empty);
+ }
+
+ /* DEBUG */
+ printf("BAT-ADC: ");
+ for(i=0;i<MADC_NUM_CHANNELS;i++)
+ printf("%3d ",bat_compal_e88_madc[i]);
+ printf("%c\n",32);
+ printf("\tCharger at %u mV.\n",battery_info.charger_volt_mV);
+ printf("\tBattery at %u mV.\n",battery_info.bat_volt_mV);
+ printf("\tCharging at %u mA.\n",battery_info.bat_chg_curr_mA);
+ printf("\tBattery capacity is %u%%.\n",battery_info.battery_percent);
+ printf("\tBattery range is %d..%d mV.\n",
+ ADC_TO_PHYSICAL(VBAT_empty,VBAT_LSB_uV),
+ ADC_TO_PHYSICAL(VBAT_full,VBAT_LSB_uV));
+ printf("\tBattery full at %d LSB .. full at %d LSB\n",VBAT_empty,VBAT_full);
+ printf("\tCharging at %d LSB (%d mA).\n",ICHG_set,
+ ADC_TO_PHYSICAL(ICHG_set,ICHG_LSB_uA));
+ i = twl3025_reg_read(BCICTL2);
+ printf("\tBCICTL2=0x%03x\n",i);
+ printf("\tbattery-info.flags=0x%08x\n",battery_info.flags);
+ printf("\tbat_compal_e88_chg_state=%d\n",bat_compal_e88_chg_state);
+}
+
+/* bat_compal_e88_adc_read() :
+ *
+ * Schedule a ADC conversion or read values from ADC. If we are
+ * running on battery, bias currents/voltage dividers are turned
+ * on on demand.
+ *
+ * Return 0 if new ADC values have been acquired, 1 if ADC
+ * has been scheduled for a new conversion or is not yet finished.
+ *
+ */
+
+enum bat_compal_e88_madc_stat {
+ ADC_CONVERSION = 1 << 0
+};
+static uint32_t bat_compal_e88_madc_stat=0;
+
+static int
+bat_compal_e88_adc_read(){
+ int i;
+
+ if(bat_compal_e88_madc_stat & ADC_CONVERSION){
+ i = twl3025_reg_read(MADCSTAT);
+ if(i & ADCBUSY)
+ return 1;
+ for(i=0;i<MADC_NUM_CHANNELS;i++)
+ bat_compal_e88_madc[i]=twl3025_reg_read(VBATREG+i);
+ /* if charger is connected, we keep the ADC and BIAS on
+ continuously, if running on battery, we try to save power */
+ if(!(battery_info.flags & BATTERY_CHG_CONNECTED)){
+ twl3025_reg_write(BCICTL1,0x00); /* turn off bias */
+ twl3025_unit_enable(TWL3025_UNIT_MAD,0); /* & ADC */
+ }
+ bat_compal_e88_madc_stat &= ~ ADC_CONVERSION;
+ return 0;
+ } else {
+ /* if running on battery, turn on ADC & BIAS on demand */
+ if(!(battery_info.flags & BATTERY_CHG_CONNECTED)){
+ twl3025_unit_enable(TWL3025_UNIT_MAD,1);
+ twl3025_reg_write(BCICTL1,BATTERY_ALL_SENSE);
+ }
+
+ twl3025_reg_write(MADCTRL,0xff); /* convert all channels */
+ twl3025_reg_write(VBATREG,0); /* trigger conversion */
+
+ bat_compal_e88_madc_stat |= ADC_CONVERSION;
+ return 1;
+ }
+}
+
+static void
+battery_compal_e88_timer_cb(void *p){
+ struct osmo_timer_list *tmr = (struct osmo_timer_list*)p;
+ int i;
+
+ if(bat_compal_e88_adc_read()){ /* read back ADCs after a brief delay */
+ osmo_timer_schedule(tmr,ADC_TIMER_DELAY);
+ return;
+ }
+
+ bat_compal_e88_upd_measurements(); /* convert user-accessible information */
+ bat_compal_e88_chk_ac_presence(); /* detect AC charger presence */
+ bat_compal_e88_chg_control(); /* battery charger state machine */
+
+ osmo_timer_schedule(tmr,BATTERY_TIMER_DELAY);
+}
+
+/* timer that fires the charging loop regularly */
+static struct osmo_timer_list battery_compal88_timer = {
+ .cb = &battery_compal_e88_timer_cb,
+ .data = &battery_compal88_timer
+};
+
+void
+battery_compal_e88_init(){
+ printf("%s: starting up\n",__FUNCTION__);
+ osmo_timer_schedule(&battery_compal88_timer,BATTERY_TIMER_DELAY);
+}
+
diff --git a/src/target/firmware/battery/dummy.c b/src/target/firmware/battery/dummy.c
new file mode 100644
index 00000000..3051a615
--- /dev/null
+++ b/src/target/firmware/battery/dummy.c
@@ -0,0 +1,9 @@
+#include <battery/battery.h>
+
+/* Battery Management: Dummy file when no charging logic exists. */
+struct battery_info battery_info;
+
+void battery_dummy_init(){
+ battery_info.flags = BATTERY_FAILURE; /* not implemented */
+}
+
diff --git a/src/target/firmware/board/common/calypso_pwl.S b/src/target/firmware/board/common/calypso_pwl.S
new file mode 100644
index 00000000..90e29bff
--- /dev/null
+++ b/src/target/firmware/board/common/calypso_pwl.S
@@ -0,0 +1,21 @@
+
+/* Calypso PWL driver */
+
+#define ASIC_CONF_REG 0xfffef008
+#define BA_PWL 0xfffe8000
+
+.globl pwl_init
+pwl_init: ldr r1, =ASIC_CONF_REG
+ ldr r2, [r1]
+ orr r2, r2, #0x10 @ set light output to PWL
+ str r2, [r1]
+ ldr r1, =BA_PWL
+ mov r0, #1
+ strb r0, [r1, #1] @ enable clock of PWL unut
+ mov pc, lr
+
+.globl pwl_set_level
+pwl_set_level: ldr r1, =BA_PWL
+ strb r0, [r1]
+ mov pc, lr
+
diff --git a/src/target/firmware/board/common/calypso_uart.S b/src/target/firmware/board/common/calypso_uart.S
new file mode 100644
index 00000000..808cb051
--- /dev/null
+++ b/src/target/firmware/board/common/calypso_uart.S
@@ -0,0 +1,92 @@
+/* uart routines for early assembly code */
+
+#define BA_UART_MODEM 0xFFFF5800
+
+.macro senduart, rd, rx
+ strb \rd, [\rx, #0]
+.endm
+
+.macro busyuart, rd, rx
+1001:
+ @busy waiting until THR is empty
+ ldrb \rd, [\rx, #5] @ read LSR register
+ mov \rd, \rd, lsr #6
+ tst \rd, #1
+ beq 1001b
+.endm
+
+.macro loadsp, rd
+ ldr \rd, =BA_UART_MODEM
+.endm
+
+.section .text
+
+ .align 2
+ .type phexbuf, #object
+phexbuf: .space 12
+ .size phexubf, . - phexbuf
+
+.globl phex
+phex: adr r3, phexbuf
+ mov r2, #0
+ strb r2, [r3, r1]
+1: subs r1, r1, #1
+ movmi r0, r3
+ bmi puts_asm
+ and r2, r0, #15
+ mov r0, r0, lsr #4
+ cmp r2, #10
+ addge r2, r2, #7
+ add r2, r2, #'0'
+ strb r2, [r3, r1]
+ b 1b
+
+.globl puts_asm
+puts_asm: loadsp r3
+1: ldrb r2, [r0], #1
+ teq r2, #0
+ moveq pc, lr
+2: senduart r2, r3
+ busyuart r1, r3
+ teq r2, #'\n'
+ moveq r2, #'\r'
+ beq 2b
+ teq r0, #0
+ bne 1b
+ mov pc, lr
+
+.globl putchar_asm
+putchar_asm:
+ mov r2, r0
+ mov r0, #0
+ loadsp r3
+ b 2b
+
+.globl memdump_asm
+memdump_asm: mov r12, r0
+ mov r10, lr
+ mov r11, #0
+2: mov r0, r11, lsl #2
+ add r0, r0, r12
+ mov r1, #8
+ bl phex
+ mov r0, #':'
+ bl putchar_asm
+1: mov r0, #' '
+ bl putchar_asm
+ ldr r0, [r12, r11, lsl #2]
+ mov r1, #8
+ bl phex
+ and r0, r11, #7
+ teq r0, #3
+ moveq r0, #' '
+ bleq putchar_asm
+ and r0, r11, #7
+ add r11, r11, #1
+ teq r0, #7
+ bne 1b
+ mov r0, #'\n'
+ bl putchar_asm
+ cmp r11, #64
+ blt 2b
+ mov pc, r10
diff --git a/src/target/firmware/board/compal/LINKAGE.txt b/src/target/firmware/board/compal/LINKAGE.txt
new file mode 100644
index 00000000..1ae06fb3
--- /dev/null
+++ b/src/target/firmware/board/compal/LINKAGE.txt
@@ -0,0 +1,12 @@
+
+We provide the following common RAM linkages for all Compal phones:
+
+(both use the Calypso ROM loader for interrupt redirect, if required)
+
+ compalram:
+ Image for the Compal ramloader. Starts at a weird address and
+ contains various ramloader specifics.
+
+ highram:
+ Image linked to 0x820000, used for various special purposes.
+ This image is completely independent of the compal loader.
diff --git a/src/target/firmware/board/compal/exceptions_redirect.S b/src/target/firmware/board/compal/exceptions_redirect.S
new file mode 100644
index 00000000..a216e601
--- /dev/null
+++ b/src/target/firmware/board/compal/exceptions_redirect.S
@@ -0,0 +1,24 @@
+
+.section .text.exceptions
+_undef_instr:
+ ldr pc, _vec_undef_instr
+_sw_interr:
+ ldr pc, _vec_sw_interr
+_prefetch_abort:
+ ldr pc, _vec_prefetch_abort
+_data_abort:
+ ldr pc, _vec_data_abort
+_reserved:
+ ldr pc, _vec_reserved
+_irq:
+ ldr pc, _vec_irq
+_fiq:
+ ldr pc, _vec_fiq
+
+_vec_undef_instr: .word(0x80001c)
+_vec_sw_interr: .word(0x800020)
+_vec_prefetch_abort: .word(0x800024)
+_vec_data_abort: .word(0x800028)
+_vec_reserved: .word(0x80002c)
+_vec_irq: .word(0x800030)
+_vec_fiq: .word(0x800034)
diff --git a/src/target/firmware/board/compal/exceptions_redirected.S b/src/target/firmware/board/compal/exceptions_redirected.S
new file mode 100644
index 00000000..69083962
--- /dev/null
+++ b/src/target/firmware/board/compal/exceptions_redirected.S
@@ -0,0 +1,20 @@
+
+/* Exception Vectors like they are needed for the exception vector
+ indirection of the internal boot ROM. The following section must be liked
+ to appear at 0x80001c */
+.section .text.exceptions
+_undef_instr:
+ b handle_abort
+_sw_interr:
+ b _sw_interr
+_prefetch_abort:
+ b handle_abort
+_data_abort:
+ b handle_abort
+_reserved:
+ b _reserved
+_irq:
+ b irq_entry
+_fiq:
+ b fiq_entry
+
diff --git a/src/target/firmware/board/compal/handlers.S b/src/target/firmware/board/compal/handlers.S
new file mode 100644
index 00000000..ef044e3f
--- /dev/null
+++ b/src/target/firmware/board/compal/handlers.S
@@ -0,0 +1,79 @@
+
+ .EQU I_BIT, 0x80
+ .EQU F_BIT, 0x40
+
+.section .text
+
+/* handler for all kinds of aborts */
+.global handle_abort
+handle_abort:
+ @ print the PC we would jump back to...
+ sub lr, lr, #4 @ we assume to be ARM32
+
+ mov r0, lr
+ mov r1, #8
+ bl phex
+
+ @ print abort message
+ mov r0, #'A'
+ bl putchar_asm
+ mov r0, #'B'
+ bl putchar_asm
+ mov r0, #'O'
+ bl putchar_asm
+ mov r0, #'R'
+ bl putchar_asm
+ mov r0, #'T'
+ bl putchar_asm
+
+ @ disable IRQ and FIQ
+ msr CPSR_c, #I_BIT | F_BIT
+
+0: @ dead
+ b 0b
+
+/* entry point for IRQs */
+.global irq_entry
+irq_entry:
+ /* Adjust and save LR_irq in IRQ stack */
+ sub lr, lr, #4
+ stmfd sp!, {lr}
+
+ /* Save SPSR for nested interrupt */
+ mrs r14, SPSR
+ stmfd sp!, {r14}
+
+ /* Call the interrupt handler C function */
+ stmfd sp!, {r0-r4, r12}
+ bl irq
+ ldmfd sp!, {r0-r4, r12}
+
+ /* Restore SPSR_irq from IRQ stack */
+ ldmia sp!, {r14}
+ msr SPSR_cxsf, r14
+
+ /* Restore adjusted LR_irq from IRQ stack directly in the PC */
+ ldmia sp!, {pc}^
+
+/* entry point for FIQs */
+.global fiq_entry
+fiq_entry:
+ /* Adjust and save LR_irq in IRQ stack */
+ sub lr, lr, #4
+ stmfd sp!, {lr}
+
+ /* Save SPSR for nested interrupt */
+ mrs r14, SPSR
+ stmfd sp!, {r14}
+
+ /* Call the interrupt handler C function */
+ stmfd sp!, {r0-r4, r12}
+ bl fiq
+ ldmfd sp!, {r0-r4, r12}
+
+ /* Restore SPSR_irq from IRQ stack */
+ ldmia sp!, {r14}
+ msr SPSR_cxsf, r14
+
+ /* Restore adjusted LR_irq from IRQ stack directly in the PC */
+ ldmia sp!, {pc}^
diff --git a/src/target/firmware/board/compal/header.S b/src/target/firmware/board/compal/header.S
new file mode 100644
index 00000000..747f6806
--- /dev/null
+++ b/src/target/firmware/board/compal/header.S
@@ -0,0 +1,11 @@
+/*
+ * This is a textual header that is prepended to images where appropriate.
+ *
+ * It is meant to ease identification of our firmwares in dumps as well
+ * as filling some space that is used for the same purpose by the vendor.
+ *
+ */
+.section .compal.header
+.ascii "OSMOCOM"
+. = 0x20
+.ascii GIT_REVISION
diff --git a/src/target/firmware/board/compal/highram.lds b/src/target/firmware/board/compal/highram.lds
new file mode 100644
index 00000000..498a2fa1
--- /dev/null
+++ b/src/target/firmware/board/compal/highram.lds
@@ -0,0 +1,121 @@
+/*
+ * Linker script for running from upper internal RAM on the TI Calypso
+ *
+ * This script creates a binary that can be loaded into high ram on
+ * all Calypso devices. It can be jumped into directly at the load
+ * address.
+ *
+ * This is used for debugging the loader and for general hacking purposes.
+ *
+ */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+MEMORY
+{
+ /* lowram: could be anything, we place exception vectors here */
+ XRAM (rw) : ORIGIN = 0x00800000, LENGTH = 0x00020000
+ /* highram binary: our text, initialized data */
+ LRAM (rw) : ORIGIN = 0x00820000, LENGTH = 0x00014000
+ /* highram binary: our unitialized data, stacks, heap */
+ IRAM (rw) : ORIGIN = 0x00834000, LENGTH = 0x0000c000
+}
+SECTIONS
+{
+ . = 0x820000;
+
+ /* initialization code */
+ .text.start : {
+ PROVIDE(_start = .);
+ KEEP(*(.text.start))
+ *(.text.start)
+ } > LRAM
+
+ /* exception vectors linked for 0x80001c to 0x800034 */
+ .text.exceptions 0x80001c : AT (LOADADDR(.text.start) + SIZEOF(.text.start)) {
+ KEEP(*(.text.exceptions))
+ * (.text.exceptions)
+ . = ALIGN(4);
+ } > XRAM
+ PROVIDE(_exceptions = LOADADDR(.text.exceptions));
+
+ /* code */
+ . = ALIGN(4);
+ .text (LOADADDR(.text.exceptions) + SIZEOF(.text.exceptions)) :
+ AT (LOADADDR(.text.exceptions) + SIZEOF(.text.exceptions)) {
+ /* regular code */
+ *(.text*)
+ /* always-in-ram code */
+ *(.ramtext*)
+ /* gcc voodoo */
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+ . = ALIGN(4);
+ } > LRAM
+ PROVIDE(_text_start = LOADADDR(.text));
+ PROVIDE(_text_end = LOADADDR(.text) + SIZEOF(.text));
+
+ /* constructor pointers */
+ .ctors : {
+ /* ctor count */
+ LONG(SIZEOF(.ctors) / 4 - 2)
+ /* ctor pointers */
+ KEEP(*(SORT(.ctors)))
+ /* end of list */
+ LONG(0)
+ } > LRAM
+ PROVIDE(_ctor_start = LOADADDR(.ctors));
+ PROVIDE(_ctor_end = LOADADDR(.ctors) + SIZEOF(.ctors));
+
+ /* destructor pointers */
+ .dtors : {
+ /* dtor count */
+ LONG(SIZEOF(.dtors) / 4 - 2)
+ /* dtor pointers */
+ KEEP(*(SORT(.dtors)))
+ /* end of list */
+ LONG(0)
+ } > LRAM
+ PROVIDE(_dtor_start = LOADADDR(.dtors));
+ PROVIDE(_dtor_end = LOADADDR(.dtors) + SIZEOF(.dtors));
+
+ /* read-only data */
+ . = ALIGN(4);
+ .rodata : {
+ *(.rodata*)
+ } > LRAM
+ PROVIDE(_rodata_start = LOADADDR(.rodata));
+ PROVIDE(_rodata_end = LOADADDR(.rodata) + SIZEOF(.rodata));
+
+ /* initialized data */
+ . = ALIGN(4);
+ .data : {
+ *(.data)
+ } > LRAM
+ PROVIDE(_data_start = LOADADDR(.data));
+ PROVIDE(_data_end = LOADADDR(.data) + SIZEOF(.data));
+
+ /* pic offset tables */
+ . = ALIGN(4);
+ .got : {
+ *(.got)
+ *(.got.plt) *(.igot.plt) *(.got) *(.igot)
+ } > LRAM
+ PROVIDE(_got_start = LOADADDR(.got));
+ PROVIDE(_got_end = LOADADDR(.got) + SIZEOF(.got));
+
+ /* uninitialized data */
+ .bss (NOLOAD) : {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss)
+ } > IRAM
+ . = ALIGN(4);
+ __bss_end = .;
+ PROVIDE(_bss_start = __bss_start);
+ PROVIDE(_bss_end = __bss_end);
+
+ /* end of image */
+ . = ALIGN(4);
+ _end = .;
+ PROVIDE(end = .);
+}
diff --git a/src/target/firmware/board/compal/macros.S b/src/target/firmware/board/compal/macros.S
new file mode 100644
index 00000000..613e6bda
--- /dev/null
+++ b/src/target/firmware/board/compal/macros.S
@@ -0,0 +1,76 @@
+
+.macro clear_bss
+ mov r0, #0
+ ldr r1, =__bss_start
+ ldr r2, =__bss_end
+loop_bss:
+ cmp r1, r2
+ strlo r0, [r1], #4
+ blo loop_bss
+.endm
+
+.macro copy_data
+ ldr r0, =__data_start
+ ldr r1, =_data_start
+ ldr r2, =__data_end
+ cmp r0, r2
+ beq done_data
+loop_data:
+ ldrb r4, [r0], #1
+ strb r4, [r1], #1
+ cmp r0, r2
+ bne loop_data
+done_data:
+.endm
+
+.macro copy_ramtext
+ ldr r0, =__ramtext_start
+ ldr r1, =_ramtext_start
+ ldr r2, =__ramtext_end
+ cmp r0, r2
+ beq done_ramtext
+loop_ramtext:
+ ldrb r4, [r0], #1
+ strb r4, [r1], #1
+ cmp r0, r2
+ bne loop_ramtext
+done_ramtext:
+.endm
+
+ .EQU ARM_MODE_FIQ, 0x11
+ .EQU ARM_MODE_IRQ, 0x12
+ .EQU ARM_MODE_SVC, 0x13
+
+ .EQU I_BIT, 0x80
+ .EQU F_BIT, 0x40
+
+#define TOP_OF_RAM 0x083fff0
+#define FIQ_STACK_SIZE 1024
+#define IRQ_STACK_SIZE 1024
+
+.macro init_stacks
+ /* initialize stacks, starting at TOP_OF_RAM */
+ ldr r0, =TOP_OF_RAM
+
+ /* initialize FIQ stack */
+ msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT
+ mov r13, r0
+ sub r0, r0, #FIQ_STACK_SIZE
+
+ /* initialize IRQ stack */
+ msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT
+ mov r13, r0
+ sub r0, r0, #IRQ_STACK_SIZE
+
+ /* initialize supervisor stack */
+ msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT
+ mov r13, r0
+.endm
+
+.macro call_ctors
+ /* call constructor functions */
+ ldr r0, =_ctor_start
+ ldr r1, =_ctor_end
+ bl do_global_ctors
+.endm
+
diff --git a/src/target/firmware/board/compal/ram.lds b/src/target/firmware/board/compal/ram.lds
new file mode 100644
index 00000000..9503edee
--- /dev/null
+++ b/src/target/firmware/board/compal/ram.lds
@@ -0,0 +1,123 @@
+/*
+ * Linker script for running from internal SRAM on Compal phones
+ *
+ * This script is tailored specifically to the requirements imposed
+ * on us by the Compal bootloader.
+ *
+ */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+MEMORY
+{
+ /* compal-loaded binary: our text, initialized data */
+ LRAM (rw) : ORIGIN = 0x00800000, LENGTH = 0x00014000
+ /* compal-loaded binary: our unitialized data, stacks, heap */
+ IRAM (rw) : ORIGIN = 0x00814000, LENGTH = 0x0000c000
+}
+SECTIONS
+{
+ . = 0x800000;
+
+ /* romloader data section, contains passthru interrupt vectors */
+ .compal.loader (NOLOAD) : { . = 0x100; } > LRAM
+
+ /* image signature (prepended by osmocon according to phone type) */
+ .compal.header (NOLOAD) : { . = 4; } > LRAM
+
+ /* initialization code */
+ . = ALIGN(4);
+ .text.start : {
+ PROVIDE(_start = .);
+ KEEP(*(.text.start))
+ *(.text.start)
+ } > LRAM
+
+ /* exception vectors from 0x80001c to 0x800034 */
+ .text.exceptions 0x80001c : AT (LOADADDR(.text.start) + SIZEOF(.text.start)) {
+ KEEP(*(.text.exceptions))
+ * (.text.exceptions)
+ . = ALIGN(4);
+ } > LRAM
+ PROVIDE(_exceptions = LOADADDR(.text.exceptions));
+
+ /* code */
+ . = ALIGN(4);
+ .text (LOADADDR(.text.exceptions) + SIZEOF(.text.exceptions)) :
+ AT (LOADADDR(.text.exceptions) + SIZEOF(.text.exceptions)) {
+ /* regular code */
+ *(.text*)
+ /* always-in-ram code */
+ *(.ramtext*)
+ /* gcc voodoo */
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+ . = ALIGN(4);
+ } > LRAM
+ PROVIDE(_text_start = LOADADDR(.text));
+ PROVIDE(_text_end = LOADADDR(.text) + SIZEOF(.text));
+
+ /* constructor pointers */
+ .ctors : {
+ /* ctor count */
+ LONG(SIZEOF(.ctors) / 4 - 2)
+ /* ctor pointers */
+ KEEP(*(SORT(.ctors)))
+ /* end of list */
+ LONG(0)
+ } > LRAM
+ PROVIDE(_ctor_start = LOADADDR(.ctors));
+ PROVIDE(_ctor_end = LOADADDR(.ctors) + SIZEOF(.ctors));
+
+ /* destructor pointers */
+ .dtors : {
+ /* dtor count */
+ LONG(SIZEOF(.dtors) / 4 - 2)
+ /* dtor pointers */
+ KEEP(*(SORT(.dtors)))
+ /* end of list */
+ LONG(0)
+ } > LRAM
+ PROVIDE(_dtor_start = LOADADDR(.dtors));
+ PROVIDE(_dtor_end = LOADADDR(.dtors) + SIZEOF(.dtors));
+
+ /* read-only data */
+ . = ALIGN(4);
+ .rodata : {
+ *(.rodata*)
+ } > LRAM
+ PROVIDE(_rodata_start = LOADADDR(.rodata));
+ PROVIDE(_rodata_end = LOADADDR(.rodata) + SIZEOF(.rodata));
+
+ /* initialized data */
+ . = ALIGN(4);
+ .data : {
+ *(.data)
+ } > LRAM
+ PROVIDE(_data_start = LOADADDR(.data));
+ PROVIDE(_data_end = LOADADDR(.data) + SIZEOF(.data));
+
+ /* pic offset tables */
+ . = ALIGN(4);
+ .got : {
+ *(.got)
+ *(.got.plt) *(.igot.plt) *(.got) *(.igot)
+ } > LRAM
+ PROVIDE(_got_start = LOADADDR(.got));
+ PROVIDE(_got_end = LOADADDR(.got) + SIZEOF(.got));
+
+ /* uninitialized data */
+ .bss (NOLOAD) : {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss)
+ } > IRAM
+ . = ALIGN(4);
+ __bss_end = .;
+ PROVIDE(_bss_start = __bss_start);
+ PROVIDE(_bss_end = __bss_end);
+
+ /* end of image */
+ . = ALIGN(4);
+ _end = .;
+ PROVIDE(end = .);
+}
diff --git a/src/target/firmware/board/compal/rf_power.c b/src/target/firmware/board/compal/rf_power.c
new file mode 100644
index 00000000..fbbe65a3
--- /dev/null
+++ b/src/target/firmware/board/compal/rf_power.c
@@ -0,0 +1,62 @@
+/* Tx RF power calibration for the Compal/Motorola dualband phones */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <osmocom/core/utils.h>
+
+/* GSM900 ARFCN 33, Measurements by Steve Markgraf / May 2010 */
+const int16_t dbm2apc_gsm900[] = {
+ [0] = 151,
+ [1] = 152,
+ [2] = 153,
+ [3] = 155,
+ [4] = 156,
+ [5] = 158,
+ [6] = 160,
+ [7] = 162,
+ [8] = 164,
+ [9] = 167,
+ [10] = 170,
+ [11] = 173,
+ [12] = 177,
+ [13] = 182,
+ [14] = 187,
+ [15] = 192,
+ [16] = 199,
+ [17] = 206,
+ [18] = 214,
+ [19] = 223,
+ [20] = 233,
+ [21] = 244,
+ [22] = 260,
+ [23] = 271,
+ [24] = 288,
+ [25] = 307,
+ [26] = 327,
+ [27] = 350,
+ [28] = 376,
+ [29] = 407,
+ [30] = 456,
+ [31] = 575,
+};
+
+const int dbm2apc_gsm900_max = ARRAY_SIZE(dbm2apc_gsm900) - 1;
diff --git a/src/target/firmware/board/compal/rffe_dualband.c b/src/target/firmware/board/compal/rffe_dualband.c
new file mode 100644
index 00000000..f4b73618
--- /dev/null
+++ b/src/target/firmware/board/compal/rffe_dualband.c
@@ -0,0 +1,102 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <rffe.h>
+#include <calypso/tsp.h>
+#include <rf/trf6151.h>
+
+/* This is a value that has been measured on the C123 by Harald: 71dBm,
+ it is the difference between the input level at the antenna and what
+ the DSP reports, subtracted by the total gain of the TRF6151 */
+#define SYSTEM_INHERENT_GAIN 71
+
+/* describe how the RF frontend is wired on the Motorola E88 board (C117/C118/C121/C123) */
+
+#define RITA_RESET TSPACT(0) /* Reset of the Rita TRF6151 */
+#define PA_ENABLE TSPACT(1) /* Enable the Power Amplifier */
+#define TRENA TSPACT(6) /* Transmit Enable (Antenna Switch) */
+#define GSM_TXEN TSPACT(8) /* GSM (as opposed to DCS) Transmit */
+
+#define IOTA_STROBE TSPEN(0) /* Strobe for the Iota TSP */
+#define RITA_STROBE TSPEN(2) /* Strobe for the Rita TSP */
+
+/* switch RF Frontend Mode */
+void rffe_mode(enum gsm_band band, int tx)
+{
+ uint16_t tspact = tsp_act_state();
+
+ /* First we mask off all bits from the state cache */
+ tspact &= ~PA_ENABLE;
+ tspact |= TRENA | GSM_TXEN; /* low-active */
+
+#ifdef CONFIG_TX_ENABLE
+ /* Then we selectively set the bits on, if required */
+ if (tx) {
+ tspact &= ~TRENA;
+ if (band == GSM_BAND_850 || band == GSM_BAND_900)
+ tspact &= ~GSM_TXEN;
+ tspact |= PA_ENABLE;
+ }
+#endif /* TRANSMIT_SUPPORT */
+
+ tsp_act_update(tspact);
+}
+
+/* Returns RF wiring */
+uint32_t rffe_get_rx_ports(void)
+{
+ return (1 << PORT_LO) | (1 << PORT_DCS1800);
+}
+
+uint32_t rffe_get_tx_ports(void)
+{
+ return (1 << PORT_LO) | (1 << PORT_HI);
+}
+
+
+#define MCU_SW_TRACE 0xfffef00e
+#define ARM_CONF_REG 0xfffef006
+
+void rffe_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ARM_CONF_REG);
+ reg &= ~ (1 << 5); /* TSPACT6 I/O function, not nCS6 */
+ writew(reg, ARM_CONF_REG);
+
+ reg = readw(MCU_SW_TRACE);
+ reg &= ~(1 << 5); /* TSPACT8 I/O function, not nMREQ */
+ writew(reg, MCU_SW_TRACE);
+
+ /* Configure the TSPEN which is connected to the TWL3025 */
+ tsp_setup(IOTA_STROBE, 1, 0, 0);
+
+ trf6151_init(RITA_STROBE, RITA_RESET);
+}
+
+uint8_t rffe_get_gain(void)
+{
+ return trf6151_get_gain();
+}
+
+void rffe_set_gain(uint8_t dbm)
+{
+ trf6151_set_gain(dbm);
+}
+
+const uint8_t system_inherent_gain = SYSTEM_INHERENT_GAIN;
+
+/* Given the expected input level of exp_inp dBm/8 and the target of target_bb
+ * dBm8, configure the RF Frontend with the respective gain */
+void rffe_compute_gain(int16_t exp_inp, int16_t target_bb)
+{
+ trf6151_compute_gain(exp_inp, target_bb);
+}
+
+void rffe_rx_win_ctrl(int16_t exp_inp, int16_t target_bb)
+{
+ /* FIXME */
+}
diff --git a/src/target/firmware/board/compal/start.ram.S b/src/target/firmware/board/compal/start.ram.S
new file mode 100644
index 00000000..c8f242c0
--- /dev/null
+++ b/src/target/firmware/board/compal/start.ram.S
@@ -0,0 +1,26 @@
+
+.section .text.start
+
+#include "macros.S"
+
+.globl _start
+_start:
+ /* clear bss section */
+ clear_bss
+
+ /* initialize all stacks */
+ init_stacks
+
+ /* call constructors */
+ call_ctors
+
+ /* jump to main */
+ ldr pc, _jump_main
+
+ /* endless loop at end of program */
+_loop:
+ b _loop
+ b _start
+
+_jump_main:
+ .word main
diff --git a/src/target/firmware/board/compal/start.rom.S b/src/target/firmware/board/compal/start.rom.S
new file mode 100644
index 00000000..211bea86
--- /dev/null
+++ b/src/target/firmware/board/compal/start.rom.S
@@ -0,0 +1,32 @@
+
+.section .text.start
+
+#include "macros.S"
+
+.globl _start
+_start:
+ /* clear bss section */
+ clear_bss
+
+ /* copy data to ram */
+ copy_data
+
+ /* copy alway-in-ram code */
+ copy_ramtext
+
+ /* initialize all stacks */
+ init_stacks
+
+ /* call constructors */
+ call_ctors
+
+ /* jump to main */
+ ldr pc, _jump_main
+
+ /* endless loop at end of program */
+_loop:
+ b _loop
+ b _start
+
+_jump_main:
+ .word main
diff --git a/src/target/firmware/board/compal_e86/init.c b/src/target/firmware/board/compal_e86/init.c
new file mode 100644
index 00000000..2d463cb2
--- /dev/null
+++ b/src/target/firmware/board/compal_e86/init.c
@@ -0,0 +1,144 @@
+/* Initialization for the Compal E86 (Motorola C139/C140) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Steve Markgraf <steve@steve-m.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <ctors.h>
+#include <memory.h>
+#include <board.h>
+#include <keypad.h>
+#include <console.h>
+#include <flash/cfi_flash.h>
+
+#include <calypso/irq.h>
+#include <calypso/clock.h>
+#include <calypso/dma.h>
+#include <calypso/rtc.h>
+#include <calypso/timer.h>
+#include <uart.h>
+#include <calypso/backlight.h>
+
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+
+#include <fb/framebuffer.h>
+
+#define ARMIO_LATCH_OUT 0xfffe4802
+#define IO_CNTL_REG 0xfffe4804
+#define ASIC_CONF_REG 0xfffef008
+
+static void board_io_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+ /* LCD Set I/O(3) / SA0 to I/O(3) mode */
+ reg &= ~( (1 << 12) | (1 << 10) | (1 << 7) | (1 << 1)) ;
+ /* don't set function pins to I2C Mode, C155 uses UWire */
+ /* TWL3025: Set SPI+RIF RX clock to rising edge */
+ reg |= (1 << 13) | (1 << 14);
+ writew(reg, ASIC_CONF_REG);
+
+ /* LCD Set I/O(3) to output mode and enable C140 backlight (IO1) */
+ /* FIXME: Put the display backlight control to backlight.c */
+ reg = readw(IO_CNTL_REG);
+ reg &= ~((1 << 3) | (1 << 1));
+ writew(reg, IO_CNTL_REG);
+
+ /* LCD Set I/O(3) output low */
+ reg = readw(ARMIO_LATCH_OUT);
+ reg &= ~(1 << 3);
+ reg |= (1 << 1);
+ writew(reg, ARMIO_LATCH_OUT);
+}
+
+void board_init(void)
+{
+ /* Disable watchdog (compal loader leaves it enabled) */
+ wdog_enable(0);
+
+ /* Configure memory interface */
+ calypso_mem_cfg(CALYPSO_nCS0, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS1, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS2, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS3, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_CS4, 0, CALYPSO_MEM_8bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS6, 0, CALYPSO_MEM_32bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS7, 0, CALYPSO_MEM_32bit, 0);
+
+ /* Set VTCXO_DIV2 = 1, configure PLL for 104 MHz and give ARM half of that */
+ calypso_clock_set(2, CALYPSO_PLL13_104_MHZ, ARM_MCLK_DIV_2);
+
+ /* Configure the RHEA bridge with some sane default values */
+ calypso_rhea_cfg(0, 0, 0xff, 0, 1, 0, 0);
+
+ /* Initialize board-specific GPIO */
+ board_io_init();
+
+ /* Enable bootrom mapping to route exception vectors to RAM */
+ calypso_bootrom(1);
+ calypso_exceptions_install();
+
+ /* Initialize interrupt controller */
+ irq_init();
+
+ /* initialize MODEM UART to be used for sercomm*/
+ uart_init(SERCOMM_UART_NR, 1);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+
+ /* initialize IRDA UART to be used for old-school console code.
+ * note: IRDA uart only accessible on C115 and C117 PCB */
+ uart_init(CONS_UART_NR, 1);
+ uart_baudrate(CONS_UART_NR, UART_115200);
+
+ /* Initialize hardware timers */
+ hwtimer_init();
+
+ /* Initialize DMA controller */
+ dma_init();
+
+ /* Initialize real time clock */
+ rtc_init();
+
+ /* Initialize system timers (uses hwtimer 2) */
+ timer_init();
+
+ /* Initialize LCD driver (uses UWire) */
+ fb_init();
+ bl_mode_pwl(1);
+ bl_level(0);
+
+ /* Initialize keypad driver */
+ keypad_init(1);
+
+ /* Initialize ABB driver (uses SPI) */
+ twl3025_init();
+
+ /* enable LEDB driver of Iota for keypad backlight */
+ twl3025_reg_write(AUXLED, 0x02);
+}
diff --git a/src/target/firmware/board/compal_e86/rffe_dualband_e86.c b/src/target/firmware/board/compal_e86/rffe_dualband_e86.c
new file mode 100644
index 00000000..25bb0997
--- /dev/null
+++ b/src/target/firmware/board/compal_e86/rffe_dualband_e86.c
@@ -0,0 +1,106 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <rffe.h>
+#include <calypso/tsp.h>
+#include <rf/trf6151.h>
+
+/* This is a value that has been measured on the C123 by Harald: 71dBm,
+ it is the difference between the input level at the antenna and what
+ the DSP reports, subtracted by the total gain of the TRF6151 */
+#define SYSTEM_INHERENT_GAIN 71
+
+/* describe how the RF frontend is wired on the Motorola E86 board (C139/C140) */
+
+#define RITA_RESET TSPACT(0) /* Reset of the Rita TRF6151 */
+#define PA_ENABLE TSPACT(1) /* Enable the Power Amplifier */
+#define DCS_TX TSPACT(6) /* DCS Transmit Enable */
+#define GSM_TX1 TSPACT(8) /* GSM Transmit Enable 1 */
+
+/* in order to save a transistor, the E86 has a second signal for GSM TX */
+#define GSM_TX2 TSPACT(2) /* GSM Transmit Enable 2 */
+
+#define IOTA_STROBE TSPEN(0) /* Strobe for the Iota TSP */
+#define RITA_STROBE TSPEN(2) /* Strobe for the Rita TSP */
+
+/* switch RF Frontend Mode */
+void rffe_mode(enum gsm_band band, int tx)
+{
+ uint16_t tspact = tsp_act_state();
+
+ /* First we mask off all bits from the state cache */
+ tspact &= ~(PA_ENABLE);
+ tspact |= DCS_TX | GSM_TX1 | GSM_TX2; /* low-active */
+
+#ifdef CONFIG_TX_ENABLE
+ /* Then we selectively set the bits on, if required */
+ if (tx) {
+ if (band == GSM_BAND_850 || band == GSM_BAND_900)
+ tspact &= ~(GSM_TX1 | GSM_TX2);
+ else
+ tspact &= ~DCS_TX;
+ tspact |= PA_ENABLE;
+ }
+#endif /* TRANSMIT_SUPPORT */
+
+ tsp_act_update(tspact);
+}
+
+/* Returns RF wiring */
+uint32_t rffe_get_rx_ports(void)
+{
+ return (1 << PORT_LO) | (1 << PORT_DCS1800);
+}
+
+uint32_t rffe_get_tx_ports(void)
+{
+ return (1 << PORT_LO) | (1 << PORT_HI);
+}
+
+
+#define MCU_SW_TRACE 0xfffef00e
+#define ARM_CONF_REG 0xfffef006
+
+void rffe_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ARM_CONF_REG);
+ reg &= ~ (1 << 5); /* TSPACT6 I/O function, not nCS6 */
+ writew(reg, ARM_CONF_REG);
+
+ reg = readw(MCU_SW_TRACE);
+ reg &= ~(1 << 5); /* TSPACT8 I/O function, not nMREQ */
+ writew(reg, MCU_SW_TRACE);
+
+ /* Configure the TSPEN which is connected to the TWL3025 */
+ tsp_setup(IOTA_STROBE, 1, 0, 0);
+
+ trf6151_init(RITA_STROBE, RITA_RESET);
+}
+
+uint8_t rffe_get_gain(void)
+{
+ return trf6151_get_gain();
+}
+
+void rffe_set_gain(uint8_t dbm)
+{
+ trf6151_set_gain(dbm);
+}
+
+const uint8_t system_inherent_gain = SYSTEM_INHERENT_GAIN;
+
+/* Given the expected input level of exp_inp dBm/8 and the target of target_bb
+ * dBm8, configure the RF Frontend with the respective gain */
+void rffe_compute_gain(int16_t exp_inp, int16_t target_bb)
+{
+ trf6151_compute_gain(exp_inp, target_bb);
+}
+
+void rffe_rx_win_ctrl(int16_t exp_inp, int16_t target_bb)
+{
+ /* FIXME */
+}
diff --git a/src/target/firmware/board/compal_e88/LINKAGE.txt b/src/target/firmware/board/compal_e88/LINKAGE.txt
new file mode 100644
index 00000000..8adaf86e
--- /dev/null
+++ b/src/target/firmware/board/compal_e88/LINKAGE.txt
@@ -0,0 +1,33 @@
+
+The Compal E88 supports the common Compal RAM linkages.
+These operate entirely from the Calypso internal RAM.
+
+Flash linkages are structured as follows:
+
+ e88loader:
+ Linked at address of original compal application (0x2000).
+ Provides interrupt vectors as expected by compal loader.
+ Allows interrupt redirection (XXX to where?).
+
+ We introduce this for the following reasons:
+ 1. We want to start our app at 0x10000, because that
+ is the first flash page after the loader page, allowing
+ us a higher degree of "unbrickability" by never reflashing
+ the bootloader.
+ 2. We want to keep the compal loader so we do not need even
+ more boot options and to allow recovery of original firmware.
+ 3. When there is a custom app in flash at 0xFFFF, just turning
+ the phone on with the compal loader would jump into an incomplete
+ motorola app. That might not even allow turning the phone off.
+ The loader provides this functionality.
+ 4. We do not want to patch the compal loader for interrupt
+ redirect and entry vectors. So we need to place something between
+ 0x2000 and 0x10000 anyway. And since there is space, why not put
+ the whole loader in there.
+ 5. This loader has a good chance of being able to read crash buffers.
+ and examining RAM without it being clobbered by a ram upload.
+
+ e88flash:
+ Our main application linkage, starting at 0x10000 and going through
+ all of flash. Data storage locations are still to be determined.
+
diff --git a/src/target/firmware/board/compal_e88/MEMORY_MAP.txt b/src/target/firmware/board/compal_e88/MEMORY_MAP.txt
new file mode 100644
index 00000000..6094aa9b
--- /dev/null
+++ b/src/target/firmware/board/compal_e88/MEMORY_MAP.txt
@@ -0,0 +1,21 @@
+The Compal E88 has the following physical memory map:
+
+ /* 2 MBytes of external flash memory */
+ FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x200000
+ /* 256 kBytes of internal zero-waitstate sram */
+ IRAM (rw) : ORIGIN = 0x00800000, LENGTH = 0x040000
+ /* 256 kBytes of external slow sram */
+ ERAM (rw) : ORIGIN = 0x01000000, LENGTH = 0x040000
+
+The flash layout, as distributed, is:
+
+ 0x00000000 0x2000 Compal loader
+ 0x00002000 >>>>>> Compal application and storage
+
+Our flash layout is:
+
+ 0x00000000 0x2000 Compal loader
+ 0x00002000 0xE000 OSMOCOM loader (see LINKAGE.txt for reasoning)
+ 0x00010000 >>>>>> OSMOCOM application and storage
+
+(XXX: determine storage location / storage descriptor location)
diff --git a/src/target/firmware/board/compal_e88/flash.lds b/src/target/firmware/board/compal_e88/flash.lds
new file mode 100644
index 00000000..cf0f6a41
--- /dev/null
+++ b/src/target/firmware/board/compal_e88/flash.lds
@@ -0,0 +1,134 @@
+/*
+ * Linker script for flashed applications on the Compal E88
+ *
+ * This script creates a binary that can be linked at 0xFFFF, starting
+ * with the second flash page. This is what a phone application or
+ * pure layer1 device uses.
+ *
+ * XXX: interrupts?
+ *
+ */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+MEMORY
+{
+ LOADR (rx) : ORIGIN = 0x00000000, LENGTH = 0x10000
+ /* 2 MBytes of external flash memory (minus loader) */
+ FLASH (rx) : ORIGIN = 0x00010000, LENGTH = 0x1F0000
+ /* 256 kBytes of internal zero-waitstate sram */
+ IRAM (rw) : ORIGIN = 0x00800000, LENGTH = 0x040000
+ /* 256 kBytes of external slow sram */
+ ERAM (rw) : ORIGIN = 0x01000000, LENGTH = 0x040000
+}
+SECTIONS
+{
+ /* entrypoint */
+ .text.start : {
+ PROVIDE(_start = .);
+ KEEP(*(.text.start))
+ *(.text.start)
+ } > FLASH
+
+ /* exception vectors from 0x80001c to 0x800034 */
+ .text.exceptions 0x80001c : {
+ KEEP(*(.text.exceptions))
+ * (.text.exceptions)
+ . = ALIGN(4);
+ } > IRAM AT> FLASH
+ PROVIDE(_exceptions = LOADADDR(.text.exceptions));
+
+ /* code */
+ .text : {
+ /* regular code */
+ *(.text*)
+ /* gcc voodoo */
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+ } > FLASH
+ PROVIDE(_text_start = ADDR(.text));
+ PROVIDE(_text_end = ADDR(.text) + SIZEOF(.text));
+
+ /* constructor pointers */
+ .ctors : {
+ /* ctor count */
+ LONG(SIZEOF(.ctors) / 4 - 2)
+ /* ctor pointers */
+ KEEP(*(SORT(.ctors)))
+ /* end of list */
+ LONG(0)
+ } > FLASH
+ PROVIDE(_ctor_start = LOADADDR(.ctors));
+ PROVIDE(_ctor_end = LOADADDR(.ctors) + SIZEOF(.ctors));
+
+ /* destructor pointers */
+ .dtors : {
+ /* dtor count */
+ LONG(SIZEOF(.dtors) / 4 - 2)
+ /* dtor pointers */
+ KEEP(*(SORT(.dtors)))
+ /* end of list */
+ LONG(0)
+ } > FLASH
+ PROVIDE(_dtor_start = LOADADDR(.dtors));
+ PROVIDE(_dtor_end = LOADADDR(.dtors) + SIZEOF(.dtors));
+
+ /* read-only data */
+ .rodata : {
+ *(.rodata*)
+ } > FLASH
+ PROVIDE(_rodata_start = ADDR(.rodata));
+ PROVIDE(_rodata_end = ADDR(.rodata) + SIZEOF(.rodata));
+
+ /* pic offset tables */
+ .got : {
+ . = ALIGN(4);
+ *(.got)
+ *(.got.plt) *(.igot.plt) *(.got) *(.igot)
+ . = ALIGN(4);
+ } > FLASH
+ PROVIDE(_got_start = ADDR(.got));
+ PROVIDE(_got_end = ADDR(.got) + SIZEOF(.got));
+
+ /* reserved ram */
+ .compal.reservedram 0x800000 (NOLOAD) : {
+ . = 0xff;
+ } > IRAM
+
+ /* initialized data */
+ .data : AT (LOADADDR(.got) + SIZEOF(.got)) {
+ . = ALIGN(4);
+ *(.data)
+ . = ALIGN(4);
+ } > IRAM
+ PROVIDE(__data_start = LOADADDR(.data));
+ PROVIDE(__data_end = LOADADDR(.data) + SIZEOF(.data));
+ PROVIDE(_data_start = ADDR(.data));
+ PROVIDE(_data_end = ADDR(.data) + SIZEOF(.data));
+
+ /* ram code */
+ .ramtext : AT (LOADADDR(.data) + SIZEOF(.data)) {
+ . = ALIGN(4);
+ *(.ramtext)
+ . = ALIGN(4);
+ } > IRAM
+ PROVIDE(__ramtext_start = LOADADDR(.ramtext));
+ PROVIDE(__ramtext_end = LOADADDR(.ramtext) + SIZEOF(.ramtext));
+ PROVIDE(_ramtext_start = ADDR(.ramtext));
+ PROVIDE(_ramtext_end = ADDR(.ramtext) + SIZEOF(.ramtext));
+
+ /* uninitialized data */
+ .bss (NOLOAD) : {
+ . = ALIGN(4);
+ *(.bss)
+ . = ALIGN(4);
+ } > IRAM
+ PROVIDE(__bss_start = ADDR(.bss));
+ PROVIDE(__bss_end = ADDR(.bss) + SIZEOF(.bss));
+ PROVIDE(_bss_start = __bss_start);
+ PROVIDE(_bss_end = __bss_end);
+
+ /* end of image */
+ . = ALIGN(4);
+ _end = .;
+ PROVIDE(end = .);
+}
diff --git a/src/target/firmware/board/compal_e88/init.c b/src/target/firmware/board/compal_e88/init.c
new file mode 100755
index 00000000..2e957311
--- /dev/null
+++ b/src/target/firmware/board/compal_e88/init.c
@@ -0,0 +1,140 @@
+/* Initialization for the Compal E88 (Motorola C115...C123) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <ctors.h>
+#include <memory.h>
+#include <board.h>
+#include <keypad.h>
+#include <console.h>
+#include <flash/cfi_flash.h>
+
+#include <calypso/irq.h>
+#include <calypso/clock.h>
+#include <calypso/dma.h>
+#include <calypso/rtc.h>
+#include <calypso/timer.h>
+#include <uart.h>
+#include <calypso/backlight.h>
+
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+#include <fb/framebuffer.h>
+#include <battery/compal_e88.h>
+
+#define ARMIO_LATCH_OUT 0xfffe4802
+#define IO_CNTL_REG 0xfffe4804
+#define ASIC_CONF_REG 0xfffef008
+
+static void board_io_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+ /* LCD Set I/O(3) / SA0 to I/O(3) mode */
+ reg &= ~(1 << 10);
+ /* Set function pins to I2C Mode */
+ reg |= ((1 << 12) | (1 << 7)); /* SCL / SDA */
+ /* TWL3025: Set SPI+RIF RX clock to rising edge */
+ reg |= (1 << 13) | (1 << 14);
+ writew(reg, ASIC_CONF_REG);
+
+ /* LCD Set I/O(3) to output mode */
+ reg = readw(IO_CNTL_REG);
+ reg &= ~(1 << 3);
+ writew(reg, IO_CNTL_REG);
+
+ /* LCD Set I/O(3) output low */
+ reg = readw(ARMIO_LATCH_OUT);
+ reg &= ~(1 << 3);
+ writew(reg, ARMIO_LATCH_OUT);
+}
+
+void board_init(void)
+{
+ /* Configure the memory interface */
+ calypso_mem_cfg(CALYPSO_nCS0, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS1, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS2, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS3, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_CS4, 0, CALYPSO_MEM_8bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS6, 0, CALYPSO_MEM_32bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS7, 0, CALYPSO_MEM_32bit, 0);
+
+ /* Set VTCXO_DIV2 = 1, configure PLL for 104 MHz and give ARM half of that */
+ calypso_clock_set(2, CALYPSO_PLL13_104_MHZ, ARM_MCLK_DIV_2);
+
+ /* Configure the RHEA bridge with some sane default values */
+ calypso_rhea_cfg(0, 0, 0xff, 0, 1, 0, 0);
+
+ /* Initialize board-specific GPIO */
+ board_io_init();
+
+ /* Enable bootrom mapping to route exception vectors to RAM */
+ calypso_bootrom(1);
+ calypso_exceptions_install();
+
+ /* Initialize interrupt controller */
+ irq_init();
+
+ /* initialize MODEM UART to be used for sercomm*/
+ uart_init(SERCOMM_UART_NR, 1);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+
+ /* Initialize IRDA UART to be used for old-school console code.
+ * note: IRDA uart only accessible on C115 and C117 PCB */
+ uart_init(CONS_UART_NR, 1);
+ uart_baudrate(CONS_UART_NR, UART_115200);
+
+ /* Initialize hardware timers */
+ hwtimer_init();
+
+ /* Initialize DMA controller */
+ dma_init();
+
+ /* Initialize real time clock */
+ rtc_init();
+
+ /* Initialize system timers (uses hwtimer 2) */
+ timer_init();
+
+ /* Initialize LCD driver (uses I2C) and backlight */
+ fb_init();
+
+ bl_mode_pwl(1);
+ bl_level(50);
+
+ /* Initialize keypad driver */
+ keypad_init(1);
+
+ /* Initialize ABB driver (uses SPI) */
+ twl3025_init();
+
+ /* Initialize the charging controller */
+ battery_compal_e88_init();
+}
diff --git a/src/target/firmware/board/compal_e88/loader.lds b/src/target/firmware/board/compal_e88/loader.lds
new file mode 100644
index 00000000..a7a001fc
--- /dev/null
+++ b/src/target/firmware/board/compal_e88/loader.lds
@@ -0,0 +1,147 @@
+/*
+ * Linker script for flashed loader on the Compal E88
+ *
+ * This script creates a binary that can replace a standard firmware
+ * located at 0x2000. It works in conjunction with the compal ramloader.
+ *
+ * The interrupt vectors and start address are at known, fixed offsets.
+ *
+ */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+MEMORY
+{
+ /* 2 MBytes of external flash memory */
+ FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x200000
+ /* 256 kBytes of internal zero-waitstate sram */
+ IRAM (rw) : ORIGIN = 0x00800000, LENGTH = 0x040000
+ /* 256 kBytes of external slow sram */
+ ERAM (rw) : ORIGIN = 0x01000000, LENGTH = 0x040000
+}
+SECTIONS
+{
+ /* Provide symbols for the compal loader */
+ .compal.loader 0x00000000 (NOLOAD) : {
+ _compal_loader_start = .;
+ . = 0x2000;
+ _compal_loader_end = .;
+ } > FLASH
+
+ /* Compal-style image header */
+ .compal.header 0x00002000 : {
+ _compal_header_start = .;
+ KEEP(*(.compal.header))
+ *(.compal.header)
+ . = 0xA0;
+ _compal_header_end = .;
+ } > FLASH
+
+ /* Compal-style vector table */
+ .compal.vectors 0x000020A0 : {
+ PROVIDE(_exceptions = .);
+ KEEP(*(.text.exceptions))
+ *(.text.exceptions)
+ } > FLASH
+
+ /* Compal-style entry point */
+ .text.start 0x000020F8 : {
+ PROVIDE(_start = .);
+ KEEP(*(.text.start))
+ *(.text.start)
+ } > FLASH
+
+ /* code */
+ .text : {
+ /* regular code */
+ *(.text*)
+ /* gcc voodoo */
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+ } > FLASH
+ PROVIDE(_text_start = ADDR(.text));
+ PROVIDE(_text_end = ADDR(.text) + SIZEOF(.text));
+
+ /* constructor pointers */
+ .ctors : {
+ /* ctor count */
+ LONG(SIZEOF(.ctors) / 4 - 2)
+ /* ctor pointers */
+ KEEP(*(SORT(.ctors)))
+ /* end of list */
+ LONG(0)
+ } > FLASH
+ PROVIDE(_ctor_start = LOADADDR(.ctors));
+ PROVIDE(_ctor_end = LOADADDR(.ctors) + SIZEOF(.ctors));
+
+ /* destructor pointers */
+ .dtors : {
+ /* dtor count */
+ LONG(SIZEOF(.dtors) / 4 - 2)
+ /* dtor pointers */
+ KEEP(*(SORT(.dtors)))
+ /* end of list */
+ LONG(0)
+ } > FLASH
+ PROVIDE(_dtor_start = LOADADDR(.dtors));
+ PROVIDE(_dtor_end = LOADADDR(.dtors) + SIZEOF(.dtors));
+
+ /* read-only data */
+ .rodata : {
+ *(.rodata*)
+ } > FLASH
+ PROVIDE(_rodata_start = ADDR(.rodata));
+ PROVIDE(_rodata_end = ADDR(.rodata) + SIZEOF(.rodata));
+
+ /* pic offset tables */
+ .got : {
+ . = ALIGN(4);
+ *(.got)
+ *(.got.plt) *(.igot.plt) *(.got) *(.igot)
+ . = ALIGN(4);
+ } > FLASH
+ PROVIDE(_got_start = ADDR(.got));
+ PROVIDE(_got_end = ADDR(.got) + SIZEOF(.got));
+
+ /* reserved ram */
+ .compal.reservedram 0x800000 (NOLOAD) : {
+ . = 0xff;
+ } > IRAM
+
+ /* initialized data */
+ .data : AT (LOADADDR(.got) + SIZEOF(.got)) {
+ . = ALIGN(4);
+ *(.data)
+ . = ALIGN(4);
+ } > IRAM
+ PROVIDE(__data_start = LOADADDR(.data));
+ PROVIDE(__data_end = LOADADDR(.data) + SIZEOF(.data));
+ PROVIDE(_data_start = ADDR(.data));
+ PROVIDE(_data_end = ADDR(.data) + SIZEOF(.data));
+
+ /* ram code */
+ .ramtext : AT (LOADADDR(.data) + SIZEOF(.data)) {
+ . = ALIGN(4);
+ *(.ramtext)
+ . = ALIGN(4);
+ } > IRAM
+ PROVIDE(__ramtext_start = LOADADDR(.ramtext));
+ PROVIDE(__ramtext_end = LOADADDR(.ramtext) + SIZEOF(.ramtext));
+ PROVIDE(_ramtext_start = ADDR(.ramtext));
+ PROVIDE(_ramtext_end = ADDR(.ramtext) + SIZEOF(.ramtext));
+
+ /* uninitialized data */
+ .bss (NOLOAD) : {
+ . = ALIGN(4);
+ *(.bss)
+ . = ALIGN(4);
+ } > IRAM
+ PROVIDE(__bss_start = ADDR(.bss));
+ PROVIDE(__bss_end = ADDR(.bss) + SIZEOF(.bss));
+ PROVIDE(_bss_start = __bss_start);
+ PROVIDE(_bss_end = __bss_end);
+
+ /* end of image */
+ . = ALIGN(4);
+ _end = .;
+ PROVIDE(end = .);
+}
diff --git a/src/target/firmware/board/compal_e99/init.c b/src/target/firmware/board/compal_e99/init.c
new file mode 100644
index 00000000..31eb978d
--- /dev/null
+++ b/src/target/firmware/board/compal_e99/init.c
@@ -0,0 +1,142 @@
+/* Initialization for the Compal E99 (Motorola C155) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Steve Markgraf <steve@steve-m.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <ctors.h>
+#include <memory.h>
+#include <board.h>
+#include <keypad.h>
+#include <console.h>
+#include <flash/cfi_flash.h>
+
+#include <calypso/irq.h>
+#include <calypso/clock.h>
+#include <calypso/dma.h>
+#include <calypso/rtc.h>
+#include <calypso/timer.h>
+#include <uart.h>
+#include <calypso/backlight.h>
+
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+
+#include <fb/framebuffer.h>
+
+#define ARMIO_LATCH_OUT 0xfffe4802
+#define IO_CNTL_REG 0xfffe4804
+#define ASIC_CONF_REG 0xfffef008
+
+static void board_io_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+ /* LCD Set I/O(3) / SA0 to I/O(3) mode */
+ reg &= ~( (1 << 12) | (1 << 10) | (1 << 7) | (1 << 1)) ;
+ /* don't set function pins to I2C Mode, C155 uses UWire */
+ /* TWL3025: Set SPI+RIF RX clock to rising edge */
+ reg |= (1 << 13) | (1 << 14);
+ writew(reg, ASIC_CONF_REG);
+
+ /* LCD Set I/O(3) to output mode and enable C155 backlight (IO1) */
+ /* FIXME: Put the display backlight control to backlight.c */
+ reg = readw(IO_CNTL_REG);
+ reg &= ~( (1 << 3) | (1 << 1));
+ writew(reg, IO_CNTL_REG);
+
+ /* LCD Set I/O(3) output low */
+ reg = readw(ARMIO_LATCH_OUT);
+ reg &= ~(1 << 3);
+ reg |= (1 << 1);
+ writew(reg, ARMIO_LATCH_OUT);
+}
+
+void board_init(void)
+{
+ /* Disable watchdog (compal loader leaves it enabled) */
+ wdog_enable(0);
+
+ /* Configure memory interface */
+ calypso_mem_cfg(CALYPSO_nCS0, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS1, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS2, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS3, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_CS4, 0, CALYPSO_MEM_8bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS6, 0, CALYPSO_MEM_32bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS7, 0, CALYPSO_MEM_32bit, 0);
+
+ /* Set VTCXO_DIV2 = 1, configure PLL for 104 MHz and give ARM half of that */
+ calypso_clock_set(2, CALYPSO_PLL13_104_MHZ, ARM_MCLK_DIV_2);
+
+ /* Configure the RHEA bridge with some sane default values */
+ calypso_rhea_cfg(0, 0, 0xff, 0, 1, 0, 0);
+
+ /* Initialize board-specific GPIO */
+ board_io_init();
+
+ /* Enable bootrom mapping to route exception vectors to RAM */
+ calypso_bootrom(1);
+ calypso_exceptions_install();
+
+ /* Initialize interrupt controller */
+ irq_init();
+
+ /* initialize MODEM UART to be used for sercomm*/
+ uart_init(SERCOMM_UART_NR, 1);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+
+ /* initialize IRDA UART to be used for old-school console code.
+ * note: IRDA uart only accessible on C115 and C117 PCB */
+ uart_init(CONS_UART_NR, 1);
+ uart_baudrate(CONS_UART_NR, UART_115200);
+
+ /* Initialize hardware timers */
+ hwtimer_init();
+
+ /* Initialize DMA controller */
+ dma_init();
+
+ /* Initialize real time clock */
+ rtc_init();
+
+ /* Initialize system timers (uses hwtimer 2) */
+ timer_init();
+
+ /* Initialize LCD driver (uses UWire) and backlight */
+ bl_mode_pwl(1);
+ bl_level(50);
+
+ fb_init();
+
+ /* Initialize keypad driver */
+ keypad_init(1);
+
+ /* Initialize ABB driver (uses SPI) */
+ twl3025_init();
+}
diff --git a/src/target/firmware/board/gta0x/init.c b/src/target/firmware/board/gta0x/init.c
new file mode 100644
index 00000000..d125e15f
--- /dev/null
+++ b/src/target/firmware/board/gta0x/init.c
@@ -0,0 +1,133 @@
+/* Initialization for the Openmoko Freerunner modem */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <ctors.h>
+#include <memory.h>
+#include <board.h>
+#include <keypad.h>
+#include <console.h>
+#include <flash/cfi_flash.h>
+
+#include <calypso/irq.h>
+#include <calypso/clock.h>
+#include <calypso/dma.h>
+#include <calypso/rtc.h>
+#include <calypso/timer.h>
+#include <uart.h>
+#include <calypso/backlight.h>
+
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+
+#define ARMIO_LATCH_OUT 0xfffe4802
+#define IO_CNTL_REG 0xfffe4804
+#define ASIC_CONF_REG 0xfffef008
+
+static void board_io_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+ /* LCD Set I/O(3) / SA0 to I/O(3) mode */
+ reg &= ~(1 << 10);
+ /* Set function pins to I2C Mode */
+ reg |= ((1 << 12) | (1 << 7)); /* SCL / SDA */
+ /* TWL3025: Set SPI+RIF RX clock to rising edge */
+ reg |= (1 << 13) | (1 << 14);
+ writew(reg, ASIC_CONF_REG);
+
+ /* LCD Set I/O(3) to output mode */
+ reg = readw(IO_CNTL_REG);
+ reg &= ~(1 << 3);
+ writew(reg, IO_CNTL_REG);
+
+ /* LCD Set I/O(3) output low */
+ reg = readw(ARMIO_LATCH_OUT);
+ reg &= ~(1 << 3);
+ writew(reg, ARMIO_LATCH_OUT);
+}
+
+void board_init(void)
+{
+ /* Configure the memory interface */
+ calypso_mem_cfg(CALYPSO_nCS0, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS1, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS2, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS3, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_CS4, 0, CALYPSO_MEM_8bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS6, 0, CALYPSO_MEM_32bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS7, 0, CALYPSO_MEM_32bit, 0);
+
+ /* Set VTCXO_DIV2 = 1, configure PLL for 104 MHz and give ARM half of that */
+ calypso_clock_set(2, CALYPSO_PLL13_104_MHZ, ARM_MCLK_DIV_2);
+
+ /* Configure the RHEA bridge with some sane default values */
+ calypso_rhea_cfg(0, 0, 0xff, 0, 1, 0, 0);
+
+ /* Initialize board-specific GPIO */
+ board_io_init();
+
+ /* Enable bootrom mapping to route exception vectors to RAM */
+ calypso_bootrom(1);
+ calypso_exceptions_install();
+
+ /* Initialize interrupt controller */
+ irq_init();
+
+ /* initialize MODEM UART to be used for sercomm*/
+ uart_init(SERCOMM_UART_NR, 1);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+
+ /* Initialize IRDA UART to be used for old-school console code.
+ * note: IRDA uart only accessible on C115 and C117 PCB */
+ uart_init(CONS_UART_NR, 1);
+ uart_baudrate(CONS_UART_NR, UART_115200);
+
+ /* Initialize hardware timers */
+ hwtimer_init();
+
+ /* Initialize DMA controller */
+ dma_init();
+
+ /* Initialize real time clock */
+ rtc_init();
+
+ /* Initialize system timers (uses hwtimer 2) */
+ timer_init();
+
+ /* Initialize LCD driver (uses I2C) and backlight */
+ bl_mode_pwl(1);
+ bl_level(50);
+
+ /* Initialize keypad driver */
+ keypad_init(1);
+
+ /* Initialize ABB driver (uses SPI) */
+ twl3025_init();
+}
diff --git a/src/target/firmware/board/gta0x/rf_power.c b/src/target/firmware/board/gta0x/rf_power.c
new file mode 100644
index 00000000..1c896f74
--- /dev/null
+++ b/src/target/firmware/board/gta0x/rf_power.c
@@ -0,0 +1,63 @@
+/* Tx RF power calibration for the FIC GTA0x phones */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <osmocom/core/utils.h>
+
+/* GSM900 ARFCN 33, Measurements by Steve Markgraf / May 2010 */
+/* FIXME those are from compal ... need real GTA calibration */
+const int16_t dbm2apc_gsm900[] = {
+ [0] = 151,
+ [1] = 152,
+ [2] = 153,
+ [3] = 155,
+ [4] = 156,
+ [5] = 158,
+ [6] = 160,
+ [7] = 162,
+ [8] = 164,
+ [9] = 167,
+ [10] = 170,
+ [11] = 173,
+ [12] = 177,
+ [13] = 182,
+ [14] = 187,
+ [15] = 192,
+ [16] = 199,
+ [17] = 206,
+ [18] = 214,
+ [19] = 223,
+ [20] = 233,
+ [21] = 244,
+ [22] = 260,
+ [23] = 271,
+ [24] = 288,
+ [25] = 307,
+ [26] = 327,
+ [27] = 350,
+ [28] = 376,
+ [29] = 407,
+ [30] = 456,
+ [31] = 575,
+};
+
+const int dbm2apc_gsm900_max = ARRAY_SIZE(dbm2apc_gsm900) - 1;
diff --git a/src/target/firmware/board/gta0x/rffe_gta0x_triband.c b/src/target/firmware/board/gta0x/rffe_gta0x_triband.c
new file mode 100644
index 00000000..f118d291
--- /dev/null
+++ b/src/target/firmware/board/gta0x/rffe_gta0x_triband.c
@@ -0,0 +1,131 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <rffe.h>
+#include <calypso/tsp.h>
+#include <rf/trf6151.h>
+
+/* This is a value that has been measured on the C123 by Harald: 71dBm,
+ it is the difference between the input level at the antenna and what
+ the DSP reports, subtracted by the total gain of the TRF6151 */
+#define SYSTEM_INHERENT_GAIN 71
+
+/* describe how the RF frontend is wired on the Openmoko GTA0x boards */
+
+#define RITA_RESET TSPACT(0) /* Reset of the Rita TRF6151 */
+#define PA_ENABLE TSPACT(9) /* Enable the Power Amplifier */
+#define GSM_TXEN TSPACT(3) /* PA GSM switch, low-active */
+
+/* All VCn controls are low-active */
+#define ASM_VC1 TSPACT(2) /* Antenna switch VC1 */
+#define ASM_VC2 TSPACT(1) /* Antenna switch VC2 */
+#define ASM_VC3 TSPACT(4) /* Antenna switch VC3 */
+
+#define IOTA_STROBE TSPEN(0) /* Strobe for the Iota TSP */
+#define RITA_STROBE TSPEN(2) /* Strobe for the Rita TSP */
+
+/* switch RF Frontend Mode */
+void rffe_mode(enum gsm_band band, int tx)
+{
+ uint16_t tspact = tsp_act_state();
+
+ /* First we mask off all bits from the state cache */
+ tspact &= ~PA_ENABLE;
+ tspact &= ~GSM_TXEN;
+ tspact |= ASM_VC1 | ASM_VC2 | ASM_VC3; /* low-active */
+
+ switch (band) {
+ case GSM_BAND_850:
+ case GSM_BAND_900:
+ case GSM_BAND_1800:
+ break;
+ case GSM_BAND_1900:
+ tspact &= ~ASM_VC2;
+ break;
+ default:
+ /* TODO return/signal error here */
+ break;
+ }
+
+#ifdef CONFIG_TX_ENABLE
+ /* Then we selectively set the bits on, if required */
+ if (tx) {
+ switch (band) {
+ case GSM_BAND_850:
+ case GSM_BAND_900:
+ tspact &= ~ASM_VC3;
+ break;
+ case GSM_BAND_1800:
+ case GSM_BAND_1900:
+ tspact &= ~ASM_VC1;
+ tspact |= ASM_VC2;
+ tspact |= GSM_TXEN;
+ break;
+ default:
+ break;
+ }
+ tspact |= PA_ENABLE;
+ }
+#endif /* TRANSMIT_SUPPORT */
+
+ tsp_act_update(tspact);
+}
+
+/* Returns RF wiring */
+uint32_t rffe_get_rx_ports(void)
+{
+ return (1 << PORT_LO) | (1 << PORT_DCS1800) | (1 << PORT_PCS1900);
+}
+
+uint32_t rffe_get_tx_ports(void)
+{
+ return (1 << PORT_LO) | (1 << PORT_HI);
+}
+
+
+#define MCU_SW_TRACE 0xfffef00e
+#define ARM_CONF_REG 0xfffef006
+
+void rffe_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ARM_CONF_REG);
+ reg &= ~ (1 << 7); /* TSPACT4 I/O function, not nRDYMEM */
+ writew(reg, ARM_CONF_REG);
+
+ reg = readw(MCU_SW_TRACE);
+ reg &= ~(1 << 1); /* TSPACT9 I/O function, not MAS(1) */
+ writew(reg, MCU_SW_TRACE);
+
+ /* Configure the TSPEN which is connected to the TWL3025 */
+ tsp_setup(IOTA_STROBE, 1, 0, 0);
+
+ trf6151_init(RITA_STROBE, RITA_RESET);
+}
+
+uint8_t rffe_get_gain(void)
+{
+ return trf6151_get_gain();
+}
+
+void rffe_set_gain(uint8_t dbm)
+{
+ trf6151_set_gain(dbm);
+}
+
+const uint8_t system_inherent_gain = SYSTEM_INHERENT_GAIN;
+
+/* Given the expected input level of exp_inp dBm/8 and the target of target_bb
+ * dBm8, configure the RF Frontend with the respective gain */
+void rffe_compute_gain(int16_t exp_inp, int16_t target_bb)
+{
+ trf6151_compute_gain(exp_inp, target_bb);
+}
+
+void rffe_rx_win_ctrl(int16_t exp_inp, int16_t target_bb)
+{
+ /* FIXME */
+}
diff --git a/src/target/firmware/board/manifest.c b/src/target/firmware/board/manifest.c
new file mode 100644
index 00000000..025a7224
--- /dev/null
+++ b/src/target/firmware/board/manifest.c
@@ -0,0 +1,7 @@
+
+#include "manifest.h"
+
+const char *manifest_application = APPLICATION;
+const char *manifest_revision = GIT_REVISION;
+const char *manifest_board = BOARD;
+const char *manifest_environment = ENVIRONMENT;
diff --git a/src/target/firmware/board/mediatek/macros.S b/src/target/firmware/board/mediatek/macros.S
new file mode 100644
index 00000000..14ee6e6a
--- /dev/null
+++ b/src/target/firmware/board/mediatek/macros.S
@@ -0,0 +1,76 @@
+
+.macro clear_bss
+ mov r0, #0
+ ldr r1, =__bss_start
+ ldr r2, =__bss_end
+loop_bss:
+ cmp r1, r2
+ strlo r0, [r1], #4
+ blo loop_bss
+.endm
+
+.macro copy_data
+ ldr r0, =__data_start
+ ldr r1, =_data_start
+ ldr r2, =__data_end
+ cmp r0, r2
+ beq done_data
+loop_data:
+ ldrb r4, [r0], #1
+ strb r4, [r1], #1
+ cmp r0, r2
+ bne loop_data
+done_data:
+.endm
+
+.macro copy_ramtext
+ ldr r0, =__ramtext_start
+ ldr r1, =_ramtext_start
+ ldr r2, =__ramtext_end
+ cmp r0, r2
+ beq done_ramtext
+loop_ramtext:
+ ldrb r4, [r0], #1
+ strb r4, [r1], #1
+ cmp r0, r2
+ bne loop_ramtext
+done_ramtext:
+.endm
+
+ .EQU ARM_MODE_FIQ, 0x11
+ .EQU ARM_MODE_IRQ, 0x12
+ .EQU ARM_MODE_SVC, 0x13
+
+ .EQU I_BIT, 0x80
+ .EQU F_BIT, 0x40
+
+#define TOP_OF_RAM 0x4000a000
+#define FIQ_STACK_SIZE 1024
+#define IRQ_STACK_SIZE 1024
+
+.macro init_stacks
+ /* initialize stacks, starting at TOP_OF_RAM */
+ ldr r0, =TOP_OF_RAM
+
+ /* initialize FIQ stack */
+ msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT
+ mov r13, r0
+ sub r0, r0, #FIQ_STACK_SIZE
+
+ /* initialize IRQ stack */
+ msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT
+ mov r13, r0
+ sub r0, r0, #IRQ_STACK_SIZE
+
+ /* initialize supervisor stack */
+ msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT
+ mov r13, r0
+.endm
+
+.macro call_ctors
+ /* call constructor functions */
+ ldr r0, =_ctor_start
+ ldr r1, =_ctor_end
+ bl do_global_ctors
+.endm
+
diff --git a/src/target/firmware/board/mediatek/ram.lds b/src/target/firmware/board/mediatek/ram.lds
new file mode 100644
index 00000000..a2af5609
--- /dev/null
+++ b/src/target/firmware/board/mediatek/ram.lds
@@ -0,0 +1,112 @@
+/*
+ * Linker script for running from internal SRAM on MTK phones
+ *
+ * This script is tailored specifically to the requirements imposed
+ * on us by the Mediatek bootloader.
+ *
+ */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+MEMORY
+{
+ /* mtk-loaded binary: our text, initialized data */
+ LRAM (rw) : ORIGIN = 0x40000000, LENGTH = 0x00006000
+ /* mtk-loaded binary: our unitialized data, stacks, heap */
+ IRAM (rw) : ORIGIN = 0x40006000, LENGTH = 0x00006000
+}
+SECTIONS
+{
+ . = 0x40000000;
+
+ /* romloader data section, contains passthru interrupt vectors */
+ .mtk.loader (NOLOAD) : { . = 0x1400; } > LRAM
+
+ /* initialization code */
+ . = ALIGN(4);
+ .text.start : {
+ PROVIDE(_start = .);
+ KEEP(*(.text.start))
+ *(.text.start)
+ } > LRAM
+
+ /* code */
+ . = ALIGN(4);
+ .text (LOADADDR(.text.start) + SIZEOF(.text.start)) :
+ AT (LOADADDR(.text.start) + SIZEOF(.text.start)) {
+ /* regular code */
+ *(.text*)
+ /* always-in-ram code */
+ *(.ramtext*)
+ /* gcc voodoo */
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+ . = ALIGN(4);
+ } > LRAM
+ PROVIDE(_text_start = LOADADDR(.text));
+ PROVIDE(_text_end = LOADADDR(.text) + SIZEOF(.text));
+
+ /* constructor pointers */
+ .ctors : {
+ /* ctor count */
+ LONG(SIZEOF(.ctors) / 4 - 2)
+ /* ctor pointers */
+ KEEP(*(SORT(.ctors)))
+ /* end of list */
+ LONG(0)
+ } > LRAM
+ PROVIDE(_ctor_start = LOADADDR(.ctors));
+ PROVIDE(_ctor_end = LOADADDR(.ctors) + SIZEOF(.ctors));
+
+ /* destructor pointers */
+ .dtors : {
+ /* dtor count */
+ LONG(SIZEOF(.dtors) / 4 - 2)
+ /* dtor pointers */
+ KEEP(*(SORT(.dtors)))
+ /* end of list */
+ LONG(0)
+ } > LRAM
+ PROVIDE(_dtor_start = LOADADDR(.dtors));
+ PROVIDE(_dtor_end = LOADADDR(.dtors) + SIZEOF(.dtors));
+
+ /* read-only data */
+ . = ALIGN(4);
+ .rodata : {
+ *(.rodata*)
+ } > LRAM
+ PROVIDE(_rodata_start = LOADADDR(.rodata));
+ PROVIDE(_rodata_end = LOADADDR(.rodata) + SIZEOF(.rodata));
+
+ /* initialized data */
+ . = ALIGN(4);
+ .data : {
+ *(.data)
+ } > LRAM
+ PROVIDE(_data_start = LOADADDR(.data));
+ PROVIDE(_data_end = LOADADDR(.data) + SIZEOF(.data));
+
+ /* pic offset tables */
+ . = ALIGN(4);
+ .got : {
+ *(.got)
+ *(.got.plt) *(.igot.plt) *(.got) *(.igot)
+ } > LRAM
+ PROVIDE(_got_start = LOADADDR(.got));
+ PROVIDE(_got_end = LOADADDR(.got) + SIZEOF(.got));
+
+ /* uninitialized data */
+ .bss (NOLOAD) : {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss)
+ } > IRAM
+ . = ALIGN(4);
+ __bss_end = .;
+ PROVIDE(_bss_start = __bss_start);
+ PROVIDE(_bss_end = __bss_end);
+
+ /* end of image */
+ . = ALIGN(4);
+ _end = .;
+ PROVIDE(end = .);
+}
diff --git a/src/target/firmware/board/mediatek/start.ram.S b/src/target/firmware/board/mediatek/start.ram.S
new file mode 100644
index 00000000..c8f242c0
--- /dev/null
+++ b/src/target/firmware/board/mediatek/start.ram.S
@@ -0,0 +1,26 @@
+
+.section .text.start
+
+#include "macros.S"
+
+.globl _start
+_start:
+ /* clear bss section */
+ clear_bss
+
+ /* initialize all stacks */
+ init_stacks
+
+ /* call constructors */
+ call_ctors
+
+ /* jump to main */
+ ldr pc, _jump_main
+
+ /* endless loop at end of program */
+_loop:
+ b _loop
+ b _start
+
+_jump_main:
+ .word main
diff --git a/src/target/firmware/board/mediatek/uart.c b/src/target/firmware/board/mediatek/uart.c
new file mode 100644
index 00000000..8e86b204
--- /dev/null
+++ b/src/target/firmware/board/mediatek/uart.c
@@ -0,0 +1,424 @@
+/* MediaTek MT62xx internal UART Driver
+ *
+ * based on the Calypso driver, so there might be some cruft from it left...
+ *
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ * (C) 2010 by Steve Markgraf <steve@steve-m.de>
+ * (C) 2011 by Wolfram Sang <wolfram@the-dreams.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <debug.h>
+#include <memory.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <defines.h>
+#include <uart.h>
+#include <console.h>
+
+#include <comm/sercomm.h>
+
+/* MT622x */
+#if 0
+#define BASE_ADDR_UART1 0x80130000
+#define BASE_ADDR_UART2 0x80180000
+#define BASE_ADDR_UART3 0x801b0000
+#endif
+
+/* MT 6235 */
+#define BASE_ADDR_UART1 0x81030000
+
+//TODO make UART2 and 3 work
+#define UART_REG(n,m) (BASE_ADDR_UART1 + (m))
+
+#define LCR7BIT 0x80
+#define LCRBFBIT 0x40
+#define MCR6BIT 0x20
+#define REG_OFFS(m) ((m) & ~(LCR7BIT|LCRBFBIT|MCR6BIT))
+/* read access LCR[7] = 0 */
+enum uart_reg {
+ RBR = 0x00,
+ IER = 0x04,
+ IIR = 0x08,
+ LCR = 0x0c,
+ MCR = 0x10,
+ LSR = 0x14,
+ MSR = 0x18,
+ SCR = 0x1c,
+ AUTOBAUD_EN = 0x20,
+ HIGHSPEED = 0x24,
+ SAMPLE_COUNT = 0x28,
+ SAMPLE_POINT = 0x2c,
+ AUTOBAUD_REG = 0x30,
+ RATE_FIX_REG = 0x34, /* undocumented */
+ AUTOBAUDSAMPLE = 0x38,
+ GUARD = 0x3c,
+ ESCAPE_DAT = 0x40,
+ ESCAPE_EN = 0x44,
+ SLEEP_EN = 0x48,
+ VFIFO_EN = 0x4c,
+/* read access LCR[7] = 1 */
+ DLL = RBR,
+ DLH = IER,
+/* read/write access LCR[7:0] = 0xbf */
+ EFR = IIR | LCRBFBIT,
+ XON1 = MCR | LCRBFBIT,
+ XON2 = LSR | LCRBFBIT,
+ XOFF1 = MSR | LCRBFBIT,
+ XOFF2 = SCR | LCRBFBIT,
+};
+
+enum fcr_bits {
+ FIFO_EN = (1 << 0),
+ RX_FIFO_CLEAR = (1 << 1),
+ TX_FIFO_CLEAR = (1 << 2),
+ DMA_MODE = (1 << 3),
+};
+#define TX_FIFO_TRIG_SHIFT 4
+#define RX_FIFO_TRIG_SHIFT 6
+
+enum iir_bits {
+ IIR_INT_PENDING = 0x01,
+ IIR_INT_TYPE = 0x3E,
+ IIR_INT_TYPE_RX_STATUS_ERROR = 0x06,
+ IIR_INT_TYPE_RX_TIMEOUT = 0x0C,
+ IIR_INT_TYPE_RBR = 0x04,
+ IIR_INT_TYPE_THR = 0x02,
+ IIR_INT_TYPE_MSR = 0x00,
+ IIR_INT_TYPE_XOFF = 0x10,
+ IIR_INT_TYPE_FLOW = 0x20,
+ IIR_FCR0_MIRROR = 0xC0,
+};
+
+
+/* enable or disable the divisor latch for access to DLL, DLH */
+static void uart_set_lcr7bit(int uart, int on)
+{
+ uint8_t reg;
+
+ reg = readb(UART_REG(uart, LCR));
+ if (on)
+ reg |= (1 << 7);
+ else
+ reg &= ~(1 << 7);
+ writeb(reg, UART_REG(uart, LCR));
+}
+
+static uint8_t old_lcr;
+static void uart_set_lcr_bf(int uart, int on)
+{
+ if (on) {
+ old_lcr = readb(UART_REG(uart, LCR));
+ writeb(0xBF, UART_REG(uart, LCR));
+ } else {
+ writeb(old_lcr, UART_REG(uart, LCR));
+ }
+}
+
+/* Enable or disable the TCR_TLR latch bit in MCR[6] */
+static void uart_set_mcr6bit(int uart, int on)
+{
+ uint8_t mcr;
+ /* we assume EFR[4] is always set to 1 */
+ mcr = readb(UART_REG(uart, MCR));
+ if (on)
+ mcr |= (1 << 6);
+ else
+ mcr &= ~(1 << 6);
+ writeb(mcr, UART_REG(uart, MCR));
+}
+
+static void uart_reg_write(int uart, enum uart_reg reg, uint8_t val)
+{
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 1);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 1);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 1);
+
+ writeb(val, UART_REG(uart, REG_OFFS(reg)));
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 0);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 0);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 0);
+}
+
+/* read from a UART register, applying any required latch bits */
+static uint8_t uart_reg_read(int uart, enum uart_reg reg)
+{
+ uint8_t ret;
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 1);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 1);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 1);
+
+ ret = readb(UART_REG(uart, REG_OFFS(reg)));
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 0);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 0);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 0);
+
+ return ret;
+}
+
+static void uart_irq_handler_cons(__unused int irqnr)
+{
+ const uint8_t uart = CONS_UART_NR;
+ uint8_t iir;
+
+ //uart_putchar_nb(uart, 'U');
+
+ iir = uart_reg_read(uart, IIR);
+ if (iir & IIR_INT_PENDING)
+ return;
+
+ switch (iir & IIR_INT_TYPE) {
+ case IIR_INT_TYPE_RBR:
+ break;
+ case IIR_INT_TYPE_THR:
+ if (cons_rb_flush() == 1) {
+ /* everything was flushed, disable RBR IRQ */
+ uint8_t ier = uart_reg_read(uart, IER);
+ ier &= ~(1 << 1);
+ uart_reg_write(uart, IER, ier);
+ }
+ break;
+ case IIR_INT_TYPE_MSR:
+ break;
+ case IIR_INT_TYPE_RX_STATUS_ERROR:
+ break;
+ case IIR_INT_TYPE_RX_TIMEOUT:
+ break;
+ case IIR_INT_TYPE_XOFF:
+ break;
+ }
+}
+
+static void uart_irq_handler_sercomm(__unused int irqnr)
+{
+ const uint8_t uart = SERCOMM_UART_NR;
+ uint8_t iir, ch;
+
+ //uart_putchar_nb(uart, 'U');
+
+ iir = uart_reg_read(uart, IIR);
+ if (iir & IIR_INT_PENDING)
+ return;
+
+ switch (iir & IIR_INT_TYPE) {
+ case IIR_INT_TYPE_RX_TIMEOUT:
+ case IIR_INT_TYPE_RBR:
+ /* as long as we have rx data available */
+ while (uart_getchar_nb(uart, &ch)) {
+ if (sercomm_drv_rx_char(ch) < 0) {
+ /* sercomm cannot receive more data right now */
+ uart_irq_enable(uart, UART_IRQ_RX_CHAR, 0);
+ }
+ }
+ break;
+ case IIR_INT_TYPE_THR:
+ /* as long as we have space in the FIFO */
+ while (!uart_tx_busy(uart)) {
+ /* get a byte from sercomm */
+ if (!sercomm_drv_pull(&ch)) {
+ /* no more bytes in sercomm, stop TX interrupts */
+ uart_irq_enable(uart, UART_IRQ_TX_EMPTY, 0);
+ break;
+ }
+ /* write the byte into the TX FIFO */
+ uart_putchar_nb(uart, ch);
+ }
+ break;
+ case IIR_INT_TYPE_MSR:
+ printf("UART IRQ MSR\n");
+ break;
+ case IIR_INT_TYPE_RX_STATUS_ERROR:
+ printf("UART IRQ RX_SE\n");
+ break;
+ case IIR_INT_TYPE_XOFF:
+ printf("UART IRQXOFF\n");
+ break;
+ }
+}
+
+void uart_init(uint8_t uart, __unused uint8_t interrupts)
+{
+ /* no interrupts, only polling so far */
+
+ uart_reg_write(uart, IER, 0x00);
+ if (uart == CONS_UART_NR) {
+ cons_init();
+ } else {
+ sercomm_init();
+ uart_irq_enable(uart, UART_IRQ_RX_CHAR, 1);
+ }
+
+ uart_reg_write(uart, AUTOBAUD_EN, 0x00); /* disable AUTOBAUD */
+ uart_reg_write(uart, EFR, 0x10); /* Enhanced Features Register */
+
+ /* no XON/XOFF flow control, ENHANCED_EN, no auto-RTS/CTS */
+ uart_reg_write(uart, EFR, (1 << 4));
+ /* enable Tx/Rx FIFO, Tx trigger at 56 spaces, Rx trigger at 60 chars */
+ //FIXME check those FIFO settings
+ uart_reg_write(uart, IIR, FIFO_EN | RX_FIFO_CLEAR | TX_FIFO_CLEAR |
+ (3 << TX_FIFO_TRIG_SHIFT) | (1 << RX_FIFO_TRIG_SHIFT));
+
+ /* RBR interrupt only when TX FIFO and TX shift register are empty */
+ uart_reg_write(uart, SCR, (1 << 0));// | (1 << 3));
+
+ /* 8 bit, 1 stop bit, no parity, no break */
+ uart_reg_write(uart, LCR, 0x03);
+
+ uart_set_lcr7bit(uart, 0);
+}
+
+void uart_poll(uint8_t uart) {
+ if(uart == CONS_UART_NR) {
+ uart_irq_handler_cons(0);
+ } else {
+ uart_irq_handler_sercomm(0);
+ }
+}
+
+void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on)
+{
+ uint8_t ier = uart_reg_read(uart, IER);
+ uint8_t mask = 0;
+
+ switch (irq) {
+ case UART_IRQ_TX_EMPTY:
+ mask = (1 << 1);
+ break;
+ case UART_IRQ_RX_CHAR:
+ mask = (1 << 0);
+ break;
+ }
+
+ if (on)
+ ier |= mask;
+ else
+ ier &= ~mask;
+
+ uart_reg_write(uart, IER, ier);
+}
+
+
+void uart_putchar_wait(uint8_t uart, int c)
+{
+ /* wait while TX FIFO indicates full */
+ while (~readb(UART_REG(uart, LSR)) & 0x20) { }
+
+ /* put character in TX FIFO */
+ writeb(c, UART_REG(uart, RBR));
+}
+
+int uart_putchar_nb(uint8_t uart, int c)
+{
+ /* if TX FIFO indicates full, abort */
+ if (~readb(UART_REG(uart, LSR)) & 0x20)
+ return 0;
+
+ writeb(c, UART_REG(uart, RBR));
+ return 1;
+}
+
+int uart_getchar_nb(uint8_t uart, uint8_t *ch)
+{
+ uint8_t lsr;
+
+ lsr = readb(UART_REG(uart, LSR));
+
+ /* something strange happened */
+ if (lsr & 0x02)
+ printf("LSR RX_OE\n");
+ if (lsr & 0x04)
+ printf("LSR RX_PE\n");
+ if (lsr & 0x08)
+ printf("LSR RX_FE\n");
+ if (lsr & 0x10)
+ printf("LSR RX_BI\n");
+ if (lsr & 0x80)
+ printf("LSR RX_FIFO_STS\n");
+
+ /* is the Rx FIFO empty? */
+ if (!(lsr & 0x01))
+ return 0;
+
+ *ch = readb(UART_REG(uart, RBR));
+ //printf("getchar_nb(%u) = %02x\n", uart, *ch);
+ return 1;
+}
+
+int uart_tx_busy(uint8_t uart)
+{
+ /* Check THRE bit (LSR[5]) to see if FIFO is full */
+ if (~readb(UART_REG(uart, LSR)) & 0x20)
+ return 1;
+ return 0;
+}
+
+#if 0
+/* 26MHz clock input (used when no PLL initialized directly after poweron) */
+static const uint16_t divider[] = {
+ [UART_38400] = 42,
+ [UART_57600] = 28,
+ [UART_115200] = 14,
+ [UART_230400] = 7,
+ [UART_460800] = 14, /* would need UART_REG(HIGHSPEED) = 1 or 2 */
+ [UART_921600] = 7, /* would need UART_REG(HIGHSPEED) = 2 */
+};
+#endif
+
+/* 52MHz clock input (after PLL init) */
+static const uint16_t divider[] = {
+ [UART_38400] = 85,
+ [UART_57600] = 56,
+ [UART_115200] = 28,
+ [UART_230400] = 14,
+ [UART_460800] = 7,
+ [UART_921600] = 7, /* would need UART_REG(HIGHSPEED) = 1 */
+};
+
+int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt)
+{
+ uint16_t div;
+
+ if (bdrt > ARRAY_SIZE(divider))
+ return -1;
+
+ div = divider[bdrt];
+ uart_set_lcr7bit(uart, 1);
+ writeb(div & 0xff, UART_REG(uart, DLL));
+ writeb(div >> 8, UART_REG(uart, DLH));
+ uart_set_lcr7bit(uart, 0);
+
+ return 0;
+}
diff --git a/src/target/firmware/board/mt62xx/init.c b/src/target/firmware/board/mt62xx/init.c
new file mode 100644
index 00000000..3f683757
--- /dev/null
+++ b/src/target/firmware/board/mt62xx/init.c
@@ -0,0 +1,139 @@
+/* Initialization for the MT62xx Basebands */
+
+/* (C) 2010 by Steve Markgraf <steve@steve-m.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <ctors.h>
+#include <memory.h>
+#include <board.h>
+#include <keypad.h>
+#include <uart.h>
+#include <console.h>
+#include <delay.h>
+
+#include <flash/cfi_flash.h>
+
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <mtk/emi.h>
+#include <mtk/mt6235.h>
+#include <mtk/system.h>
+
+void pll_init(void)
+{
+ /* Power on PLL */
+ writew(0, MTK_PLL_PDN_CON);
+ writew(PLL_CLKSQ_DIV2_DSP | PLL_CLKSQ_DIV2_MCU, MTK_PLL_CLK_CON);
+
+ writew(PLL_RST, MTK_PLL_PLL);
+ writew(0, MTK_PLL_PLL);
+ delay_ms(1);
+
+ /* Turn on PLL for MCU, DSP and USB */
+ writew(PLL_MPLLSEL_PLL | PLL_DPLLSEL | PLL_UPLLSEL, MTK_PLL_PLL);
+
+ /*
+ * Setup MCU clock register:
+ * ARMCLK = 208MHz, AHBx4CLK = 52MHz, AHBx8CLK = 104MHz
+ * we have to write to the read-only part (EMICLK) as well, otherwise
+ * the EMI won't work! (datasheet lies)
+ */
+ writew(7 << MCUCLK_CON_AHBX8CLK_SHIFT |
+ 3 << MCUCLK_CON_AHBX4CLK_SHIFT |
+ 15 << MCUCLK_CON_ARMCLK_SHIFT |
+ 7 << MCUCLK_CON_EMICLK_SHIFT,
+ MTK_CONFG_MCUCLK_CON);
+}
+
+void memory_init(void)
+{
+ int i;
+
+ /* Initialization for Hynix RAM */
+
+ /* Configure DRAM controller */
+ writel(0x0001000e, MTK_EMI_GEND);
+ writel(0x00088a0a, MTK_EMI_GENA);
+ writel(0x00000280, MTK_EMI_GENB);
+ writel(0x52945294, MTK_EMI_GENC);
+ writel(0x1c016605, MTK_EMI_CONL);
+ writel(0x00002828, MTK_EMI_CONM);
+ writel(0x02334000, MTK_EMI_CONI);
+ writel(0x16c12212, MTK_EMI_CONJ);
+ writel(0x032d0000, MTK_EMI_CONK);
+
+ for (i = 0; i < 5; ++i) {
+ /* Setup five single bits, one by one for DRAM init */
+ writel((1 << (24 + i)) | (0x400013), MTK_EMI_CONN);
+ delay_ms(1);
+ writel(0x400013, MTK_EMI_CONN);
+ delay_ms(1);
+ }
+
+#if 0
+ /* Initialization for Toshiba RAM */
+
+ /* Configure DRAM controller */
+ writel(0x0001000E, MTK_EMI_GEND);
+ writel(0x00088E3A, MTK_EMI_GENA);
+ writel(0x000000C0, MTK_EMI_GENB);
+ writel(0x18C618C6, MTK_EMI_GENC);
+ writel(0x18007505, MTK_EMI_CONL);
+ writel(0x00002828, MTK_EMI_CONM);
+ writel(0x00332000, MTK_EMI_CONI);
+ writel(0x3CD24431, MTK_EMI_CONJ);
+ writel(0x02000000, MTK_EMI_CONK);
+
+ for (i = 0; i < 5; ++i) {
+ /* Setup five single bits, one by one for DRAM init */
+ writel((1 << (24 + i)) | (0x500013), MTK_EMI_CONN);
+ delay_ms(1);
+ writel(0x500013, MTK_EMI_CONN);
+ delay_ms(1);
+ }
+
+#endif
+}
+
+void board_init(void)
+{
+ /* powerup the baseband */
+ writew(POWERKEY1_MAGIC, MTK_RTC_POWERKEY1);
+ writew(POWERKEY2_MAGIC, MTK_RTC_POWERKEY2);
+ writew(BBPU_MAGIC | RTC_BBPU_WRITE_EN |
+ RTC_BBPU_BBPU | RTC_BBPU_AUTO,
+ MTK_RTC_BBPU);
+ writew(1, MTK_RTC_WRTGR);
+
+ /* disable watchdog timer */
+ writew(WDT_MODE_KEY, MTK_RGU_WDT_MODE);
+
+ pll_init();
+ memory_init();
+
+ /* Initialize UART without interrupts */
+ uart_init(SERCOMM_UART_NR, 0);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+}
diff --git a/src/target/firmware/board/pirelli_dpl10/init.c b/src/target/firmware/board/pirelli_dpl10/init.c
new file mode 100644
index 00000000..ef184033
--- /dev/null
+++ b/src/target/firmware/board/pirelli_dpl10/init.c
@@ -0,0 +1,149 @@
+/* Initialization for the Pirelli DP-L10 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2011-12 by Steve Markgraf <steve@steve-m.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <ctors.h>
+#include <memory.h>
+#include <board.h>
+#include <keypad.h>
+#include <console.h>
+#include <flash/cfi_flash.h>
+
+#include <calypso/irq.h>
+#include <calypso/clock.h>
+#include <calypso/dma.h>
+#include <calypso/rtc.h>
+#include <calypso/timer.h>
+#include <uart.h>
+#include <calypso/backlight.h>
+
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+
+#include <fb/framebuffer.h>
+
+#define ARMIO_LATCH_OUT 0xfffe4802
+#define IO_CNTL_REG 0xfffe4804
+#define ASIC_CONF_REG 0xfffef008
+#define IO_CONF_REG 0xfffef00a
+
+static void board_io_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+ /* Set function pins to I2C Mode */
+ reg |= ((1 << 12) | (1 << 7)); /* SCL / SDA */
+ /* TWL3025: Set SPI+RIF RX clock to rising edge */
+ reg |= (1 << 13) | (1 << 14);
+ reg &= ~(1 << 1);
+ writew(reg, ASIC_CONF_REG);
+
+ /* enable IO functionality */
+ reg = readw(IO_CONF_REG);
+ reg |= (1 << 9) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0);
+ writew(reg, IO_CONF_REG);
+
+ /* set IO directions */
+ reg = readw(IO_CNTL_REG);
+ reg &= ~((1 << 7) | (1 << 4) | (1 << 1));
+ writew(reg, IO_CNTL_REG);
+
+ /* reset display controller, disable bypass mode, set nCS4 to display */
+ reg = readw(ARMIO_LATCH_OUT);
+ reg &= ~(1 << 4);
+ writew(reg, ARMIO_LATCH_OUT);
+ reg &= ~(1 << 7);
+ reg |= (1 << 4) | (1 << 1);
+ writew(reg, ARMIO_LATCH_OUT);
+}
+
+void board_init(void)
+{
+ /* Configure the memory interface */
+ calypso_mem_cfg(CALYPSO_nCS0, 4, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS1, 4, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS2, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS3, 4, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_CS4, 7, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS6, 0, CALYPSO_MEM_32bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS7, 0, CALYPSO_MEM_32bit, 0);
+
+ /* Set VTCXO_DIV2 = 1, configure PLL for 104 MHz and give ARM half of that */
+ calypso_clock_set(2, CALYPSO_PLL13_104_MHZ, ARM_MCLK_DIV_2);
+
+ /* Configure the RHEA bridge with some sane default values */
+ calypso_rhea_cfg(0, 0, 0xff, 0, 1, 0, 0);
+
+ /* Initialize board-specific GPIO */
+ board_io_init();
+
+ /* Enable bootrom mapping to route exception vectors to RAM */
+ calypso_bootrom(1);
+ calypso_exceptions_install();
+
+ /* Initialize interrupt controller */
+ irq_init();
+
+ /* initialize MODEM UART to be used for sercomm*/
+ uart_init(SERCOMM_UART_NR, 1);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+
+ /* Initialize IRDA UART to be used for old-school console code.
+ * note: IRDA uart only accessible on C115 and C117 PCB */
+ uart_init(CONS_UART_NR, 1);
+ uart_baudrate(CONS_UART_NR, UART_115200);
+
+ /* Initialize hardware timers */
+ hwtimer_init();
+
+ /* Initialize DMA controller */
+ dma_init();
+
+ /* Initialize real time clock */
+ rtc_init();
+
+ /* Initialize system timers (uses hwtimer 2) */
+ timer_init();
+
+ /* Initialize LCD driver and backlight (0 is max, 255 min brightness) */
+ bl_mode_pwl(1);
+ bl_level(50);
+
+ fb_init();
+
+ /* Initialize keypad driver */
+ keypad_init(1);
+
+ /* Initialize ABB driver (uses SPI) */
+ twl3025_init();
+
+ /* enable LEDB driver of Iota for keypad backlight */
+ twl3025_reg_write(AUXLED, 0x02);
+}
diff --git a/src/target/firmware/board/pirelli_dpl10/rf_power.c b/src/target/firmware/board/pirelli_dpl10/rf_power.c
new file mode 100644
index 00000000..9b89847d
--- /dev/null
+++ b/src/target/firmware/board/pirelli_dpl10/rf_power.c
@@ -0,0 +1,63 @@
+/* Tx RF power calibration for the Pirelli DP-L10 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <osmocom/core/utils.h>
+
+/* GSM900 ARFCN 33, Measurements by Steve Markgraf / May 2010 */
+/* FIXME those are from the Compal phones, do measurements with the DP-L10 */
+const int16_t dbm2apc_gsm900[] = {
+ [0] = 151,
+ [1] = 152,
+ [2] = 153,
+ [3] = 155,
+ [4] = 156,
+ [5] = 158,
+ [6] = 160,
+ [7] = 162,
+ [8] = 164,
+ [9] = 167,
+ [10] = 170,
+ [11] = 173,
+ [12] = 177,
+ [13] = 182,
+ [14] = 187,
+ [15] = 192,
+ [16] = 199,
+ [17] = 206,
+ [18] = 214,
+ [19] = 223,
+ [20] = 233,
+ [21] = 244,
+ [22] = 260,
+ [23] = 271,
+ [24] = 288,
+ [25] = 307,
+ [26] = 327,
+ [27] = 350,
+ [28] = 376,
+ [29] = 407,
+ [30] = 456,
+ [31] = 575,
+};
+
+const int dbm2apc_gsm900_max = ARRAY_SIZE(dbm2apc_gsm900) - 1;
diff --git a/src/target/firmware/board/pirelli_dpl10/rffe_dpl10_triband.c b/src/target/firmware/board/pirelli_dpl10/rffe_dpl10_triband.c
new file mode 100644
index 00000000..d4d13424
--- /dev/null
+++ b/src/target/firmware/board/pirelli_dpl10/rffe_dpl10_triband.c
@@ -0,0 +1,136 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <rffe.h>
+#include <calypso/tsp.h>
+#include <rf/trf6151.h>
+
+/* This is a value that has been measured on the C123 by Harald: 71dBm,
+ it is the difference between the input level at the antenna and what
+ the DSP reports, subtracted by the total gain of the TRF6151 */
+#define SYSTEM_INHERENT_GAIN 71
+
+/* describe how the RF frontend is wired on the Pirelli DP-L10 */
+
+#define RITA_RESET TSPACT(5) /* Reset of the Rita TRF6151 */
+#define PA_ENABLE TSPACT(0) /* Enable the Power Amplifier */
+#define GSM_TXEN TSPACT(3) /* PA GSM switch, low-active,
+ * 1 for DCS1800/PCS1900 TX */
+
+/* All VCn controls are high-active */
+#define ASM_VC1 TSPACT(4) /* VC1 PCS1900 RX */
+#define ASM_VC2 TSPACT(10) /* VC2 DCS1800/PCS1900 TX */
+#define ASM_VC3 TSPACT(11) /* VC3 GSM900 TX */
+
+#define IOTA_STROBE TSPEN(0) /* Strobe for the Iota TSP */
+#define RITA_STROBE TSPEN(1) /* Strobe for the Rita TSP */
+
+/* switch RF Frontend Mode */
+void rffe_mode(enum gsm_band band, int tx)
+{
+ uint16_t tspact = tsp_act_state();
+
+ /* First we mask off all bits from the state cache */
+ tspact &= ~(PA_ENABLE| GSM_TXEN);
+ tspact &= ~(ASM_VC1 | ASM_VC2 | ASM_VC3);
+
+ switch (band) {
+ case GSM_BAND_850:
+ case GSM_BAND_900:
+ case GSM_BAND_1800:
+ break;
+ case GSM_BAND_1900:
+ tspact |= ASM_VC1;
+ break;
+ default:
+ /* TODO return/signal error here */
+ break;
+ }
+
+#ifdef CONFIG_TX_ENABLE
+ /* Then we selectively set the bits on, if required */
+ if (tx) {
+ switch (band) {
+ case GSM_BAND_850:
+ case GSM_BAND_900:
+ tspact |= ASM_VC3;
+ break;
+ case GSM_BAND_1800:
+ case GSM_BAND_1900:
+ tspact |= GSM_TXEN;
+ tspact |= ASM_VC2;
+ break;
+ default:
+ break;
+ }
+ tspact |= PA_ENABLE;
+ }
+#endif /* TRANSMIT_SUPPORT */
+
+ tsp_act_update(tspact);
+}
+
+/* Returns RF wiring */
+uint32_t rffe_get_rx_ports(void)
+{
+ return (1 << PORT_LO) | (1 << PORT_DCS1800) | (1 << PORT_PCS1900);
+}
+
+uint32_t rffe_get_tx_ports(void)
+{
+ return (1 << PORT_LO) | (1 << PORT_HI);
+}
+
+
+#define MCU_SW_TRACE 0xfffef00e
+#define ARM_CONF_REG 0xfffef006
+#define ASIC_CONF_REG 0xfffef008
+
+void rffe_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ARM_CONF_REG);
+ reg &= ~ (1 << 7); /* TSPACT4 I/O function, not nRDYMEM */
+ writew(reg, ARM_CONF_REG);
+
+ reg = readw(ASIC_CONF_REG);
+ reg &= ~ (1 << 15); /* TSPACT5 I/O function, not DPLLCLK */
+ writew(reg, ASIC_CONF_REG);
+
+ reg = readw(MCU_SW_TRACE);
+ reg &= ~(1 << 3); /* TSPACT10 I/O function, not nWAIT(1) */
+ reg &= ~(1 << 2); /* TSPACT11 I/O function, not MCLK(1) */
+ writew(reg, MCU_SW_TRACE);
+
+ /* Configure the TSPEN which is connected to the TWL3025 */
+ tsp_setup(IOTA_STROBE, 1, 0, 0);
+
+ trf6151_init(RITA_STROBE, RITA_RESET);
+}
+
+uint8_t rffe_get_gain(void)
+{
+ return trf6151_get_gain();
+}
+
+void rffe_set_gain(uint8_t dbm)
+{
+ trf6151_set_gain(dbm);
+}
+
+const uint8_t system_inherent_gain = SYSTEM_INHERENT_GAIN;
+
+/* Given the expected input level of exp_inp dBm/8 and the target of target_bb
+ * dBm8, configure the RF Frontend with the respective gain */
+void rffe_compute_gain(int16_t exp_inp, int16_t target_bb)
+{
+ trf6151_compute_gain(exp_inp, target_bb);
+}
+
+void rffe_rx_win_ctrl(int16_t exp_inp, int16_t target_bb)
+{
+ /* FIXME */
+}
diff --git a/src/target/firmware/board/se_j100/init.c b/src/target/firmware/board/se_j100/init.c
new file mode 100644
index 00000000..2a3de0ed
--- /dev/null
+++ b/src/target/firmware/board/se_j100/init.c
@@ -0,0 +1,141 @@
+/* Initialization for the Sony Ericsson J100 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010-11 by Steve Markgraf <steve@steve-m.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <ctors.h>
+#include <memory.h>
+#include <board.h>
+#include <keypad.h>
+#include <console.h>
+#include <flash/cfi_flash.h>
+
+#include <calypso/irq.h>
+#include <calypso/clock.h>
+#include <calypso/dma.h>
+#include <calypso/rtc.h>
+#include <calypso/timer.h>
+#include <uart.h>
+#include <calypso/backlight.h>
+
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+
+#include <fb/framebuffer.h>
+
+#define ARMIO_LATCH_OUT 0xfffe4802
+#define IO_CNTL_REG 0xfffe4804
+#define ASIC_CONF_REG 0xfffef008
+
+static void board_io_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+ /* LCD Set I/O(3) / SA0 to I/O(3) mode */
+ reg &= ~( (1 << 12) | (1 << 10) | (1 << 7) | (1 << 1)) ;
+ /* don't set function pins to I2C Mode, J100 uses UWire */
+ /* TWL3025: Set SPI+RIF RX clock to rising edge */
+ reg |= (1 << 13) | (1 << 14);
+ writew(reg, ASIC_CONF_REG);
+
+ /* LCD Set I/O(3) to output mode and enable C155 backlight (IO1) */
+ /* FIXME: Put the display backlight control to backlight.c */
+ reg = readw(IO_CNTL_REG);
+ reg &= ~( (1 << 3) | (1 << 1));
+ writew(reg, IO_CNTL_REG);
+
+ /* LCD Set I/O(3) output low */
+ reg = readw(ARMIO_LATCH_OUT);
+ reg &= ~(1 << 3);
+ reg |= (1 << 1);
+ writew(reg, ARMIO_LATCH_OUT);
+}
+
+void board_init(void)
+{
+ /* Disable watchdog (compal loader leaves it enabled) */
+ wdog_enable(0);
+
+ /* Configure memory interface */
+ calypso_mem_cfg(CALYPSO_nCS0, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS1, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS2, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS3, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_CS4, 0, CALYPSO_MEM_8bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS6, 0, CALYPSO_MEM_32bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS7, 0, CALYPSO_MEM_32bit, 0);
+
+ /* Set VTCXO_DIV2 = 1, configure PLL for 104 MHz and give ARM half of that */
+ calypso_clock_set(2, CALYPSO_PLL13_104_MHZ, ARM_MCLK_DIV_2);
+
+ /* Configure the RHEA bridge with some sane default values */
+ calypso_rhea_cfg(0, 0, 0xff, 0, 1, 0, 0);
+
+ /* Initialize board-specific GPIO */
+ board_io_init();
+
+ /* Enable bootrom mapping to route exception vectors to RAM */
+ calypso_bootrom(1);
+ calypso_exceptions_install();
+
+ /* Initialize interrupt controller */
+ irq_init();
+
+ /* initialize MODEM UART to be used for sercomm*/
+ uart_init(SERCOMM_UART_NR, 1);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+
+ /* initialize IRDA UART to be used for old-school console code.
+ * note: IRDA uart only accessible on C115 and C117 PCB */
+ uart_init(CONS_UART_NR, 1);
+ uart_baudrate(CONS_UART_NR, UART_115200);
+
+ /* Initialize hardware timers */
+ hwtimer_init();
+
+ /* Initialize DMA controller */
+ dma_init();
+
+ /* Initialize real time clock */
+ rtc_init();
+
+ /* Initialize system timers (uses hwtimer 2) */
+ timer_init();
+
+ /* Initialize LCD driver (uses UWire) and backlight */
+ fb_init();
+ bl_mode_pwl(1);
+ bl_level(50);
+
+ /* Initialize keypad driver */
+ keypad_init(1);
+
+ /* Initialize ABB driver (uses SPI) */
+ twl3025_init();
+}
diff --git a/src/target/firmware/calypso/Makefile b/src/target/firmware/calypso/Makefile
new file mode 100644
index 00000000..610a82c0
--- /dev/null
+++ b/src/target/firmware/calypso/Makefile
@@ -0,0 +1,4 @@
+
+LIBRARIES+=calypso
+calypso_DIR=calypso
+calypso_SRCS=arm.c buzzer.c clock.c dma.c dsp.c du.c i2c.c irq.c rtc.c sim.c spi.c tpu.c tsp.c keypad.c misc.c timer.c backlight.c uart.c uwire.c
diff --git a/src/target/firmware/calypso/arm.c b/src/target/firmware/calypso/arm.c
new file mode 100644
index 00000000..8794ee35
--- /dev/null
+++ b/src/target/firmware/calypso/arm.c
@@ -0,0 +1,26 @@
+
+/* enable IRQ+FIQ interrupts */
+void arm_enable_interrupts (void)
+{
+ unsigned long temp;
+ __asm__ __volatile__("mrs %0, cpsr\n"
+ "bic %0, %0, #0xc0\n"
+ "msr cpsr_c, %0"
+ : "=r" (temp)
+ :
+ : "memory");
+}
+
+/* disable IRQ/FIQ interrupts
+ * returns true if interrupts had been enabled before we disabled them */
+int arm_disable_interrupts(void)
+{
+ unsigned long old,temp;
+ __asm__ __volatile__("mrs %0, cpsr\n"
+ "orr %1, %0, #0xc0\n"
+ "msr cpsr_c, %1"
+ : "=r" (old), "=r" (temp)
+ :
+ : "memory");
+ return (old & 0x80) == 0;
+}
diff --git a/src/target/firmware/calypso/backlight.c b/src/target/firmware/calypso/backlight.c
new file mode 100644
index 00000000..cf29984a
--- /dev/null
+++ b/src/target/firmware/calypso/backlight.c
@@ -0,0 +1,69 @@
+/* Calypso DBB internal PWL (Pulse Width / Light) Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <memory.h>
+
+#define BASE_ADDR_PWL 0xfffe8000
+#define PWL_REG(m) (BASE_ADDR_PWL + (m))
+
+#define ASIC_CONF_REG 0xfffef008
+#define LIGHT_LEVEL_REG 0xfffe4810
+
+enum pwl_reg {
+ PWL_LEVEL = 0,
+ PWL_CTRL = 1,
+};
+
+#define ASCONF_PWL_ENA (1 << 4)
+
+void bl_mode_pwl(int on)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+
+ if (on) {
+ /* Enable pwl */
+ writeb(0x01, PWL_REG(PWL_CTRL));
+ /* Switch pin from LT to PWL */
+ reg |= ASCONF_PWL_ENA;
+ writew(reg, ASIC_CONF_REG);
+ } else {
+ /* Switch pin from PWL to LT */
+ reg &= ~ASCONF_PWL_ENA;
+ writew(reg, ASIC_CONF_REG);
+ /* Disable pwl */
+ writeb(0x00, PWL_REG(PWL_CTRL));
+ }
+}
+
+void bl_level(uint8_t level)
+{
+ if (readw(ASIC_CONF_REG) & ASCONF_PWL_ENA) {
+ writeb(level, PWL_REG(PWL_LEVEL));
+ } else {
+ /* we need to scale the light level, as the
+ * ARMIO light controller only knows 0..63 */
+ writeb(level>>2, LIGHT_LEVEL_REG);
+ }
+}
diff --git a/src/target/firmware/calypso/buzzer.c b/src/target/firmware/calypso/buzzer.c
new file mode 100644
index 00000000..e76906f9
--- /dev/null
+++ b/src/target/firmware/calypso/buzzer.c
@@ -0,0 +1,86 @@
+/* Calypso DBB internal PWT (Pulse Width / T) Buzzer Driver */
+
+/* (C) 2010 by Jose Pereira <onaips@gmail.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <memory.h>
+
+#define BASE_ADDR_PWL 0xfffe8800
+#define PWT_REG(m) (BASE_ADDR_PWL + (m))
+
+#define ASIC_CONF_REG 0xfffef008
+#define BUZZ_LEVEL_REG 0xfffe480e
+
+enum pwt_reg {
+ FRC_REG = 0,
+ VRC_REG = 1,
+ GCR_REG = 2,
+};
+
+#define ASCONF_PWT_ENA (1 << 5)
+
+void buzzer_mode_pwt(int on)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+
+ if (on) {
+ /* Enable pwt */
+ writeb(0x01, PWT_REG(GCR_REG));
+ /* Switch pin from LT to PWL */
+ reg |= ASCONF_PWT_ENA;
+ writew(reg, ASIC_CONF_REG);
+ } else {
+ /* Switch pin from PWT to BU */
+ reg |= ~ASCONF_PWT_ENA;
+ writew(reg, ASIC_CONF_REG);
+ /* Disable pwt */
+ writeb(0x00, PWT_REG(GCR_REG));
+ }
+}
+
+void buzzer_volume(uint8_t level)
+{
+
+ if (readw(ASIC_CONF_REG) & ASCONF_PWT_ENA) {
+
+ if (level) {
+ //scaling the volume as pwt only knows 0..63
+ level = level >> 1;
+ //if level > 0 buzzer is on
+ level |= 0x01;
+ }
+
+ writeb(level,PWT_REG(VRC_REG));
+
+ } else {
+ /* we need to scale the buzz level, as the
+ * ARMIO buzz controller only knows 0..63 */
+ writeb(level>>2, BUZZ_LEVEL_REG);
+ }
+}
+
+void buzzer_note(uint8_t note)
+{
+ if ( (readw(ASIC_CONF_REG) & ASCONF_PWT_ENA) )
+ writeb(note,PWT_REG(FRC_REG));
+}
diff --git a/src/target/firmware/calypso/clock.c b/src/target/firmware/calypso/clock.c
new file mode 100644
index 00000000..246b6e00
--- /dev/null
+++ b/src/target/firmware/calypso/clock.c
@@ -0,0 +1,200 @@
+/* Driver for Calypso clock management */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+//#define DEBUG
+#include <debug.h>
+
+#include <memory.h>
+#include <calypso/clock.h>
+
+#define REG_DPLL 0xffff9800
+#define DPLL_LOCK (1 << 0)
+#define DPLL_BREAKLN (1 << 1)
+#define DPLL_BYPASS_DIV_SHIFT 2 /* 2 bits */
+#define DPLL_PLL_ENABLE (1 << 4)
+#define DPLL_PLL_DIV_SHIFT 5 /* 2 bits */
+#define DPLL_PLL_MULT_SHIFT 7 /* 5 bits */
+#define DPLL_TEST (1 << 12)
+#define DPLL_IOB (1 << 13) /* Initialize on break */
+#define DPLL_IAI (1 << 14) /* Initialize after Idle */
+
+#define BASE_ADDR_CLKM 0xfffffd00
+#define CLKM_REG(m) (BASE_ADDR_CLKM+(m))
+
+enum clkm_reg {
+ CNTL_ARM_CLK = 0,
+ CNTL_CLK = 2,
+ CNTL_RST = 4,
+ CNTL_ARM_DIV = 8,
+};
+
+/* CNTL_ARM_CLK */
+#define ARM_CLK_BIG_SLEEP (1 << 0) /* MCU Master Clock enabled? */
+#define ARM_CLK_CLKIN_SEL0 (1 << 1) /* MCU source clock (0 = DPLL output, 1 = VTCXO or CLKIN */
+#define ARM_CLK_CLKIN_SEL (1 << 2) /* 0 = VTCXO or 1 = CLKIN */
+#define ARM_CLK_MCLK_DIV5 (1 << 3) /* enable 1.5 or 2.5 division factor */
+#define ARM_CLK_MCLK_DIV_SHIFT 4 /* 3 bits */
+#define ARM_CLK_DEEP_POWER_SHIFT 8
+#define ARM_CLK_DEEP_SLEEP 12
+
+/* CNTL_CLK */
+#define CLK_IRQ_CLK_DIS (1 << 0) /* IRQ clock control (0 always, 1 according ARM_MCLK_EN) */
+#define CLK_BRIDGE_CLK_DIS (1 << 1)
+#define CLK_TIMER_CLK_DIS (1 << 2)
+#define CLK_DPLL_DIS (1 << 3) /* 0: DPLL is not stopped during SLEEP */
+#define CLK_CLKOUT_EN (1 << 4) /* Enable CLKOUT output pins */
+#define CLK_EN_IDLE3_FLG (1 << 5) /* DSP idle flag control (1 =
+ * SAM/HOM register forced to HOM when DSP IDLE3) */
+#define CLK_VCLKOUT_DIV2 (1 << 6) /* 1: VCLKOUT-FR is divided by 2 */
+#define CLK_VTCXO_DIV2 (1 << 7) /* 1: VTCXO is dividied by 2 */
+
+#define BASE_ADDR_MEMIF 0xfffffb00
+#define MEMIF_REG(x) (BASE_ADDR_MEMIF+(x))
+
+enum memif_reg {
+ API_RHEA_CTL = 0x0e,
+ EXTRA_CONF = 0x10,
+};
+
+static void dump_reg16(uint32_t addr, char *name)
+{
+ printf("%s=0x%04x\n", name, readw(addr));
+}
+
+void calypso_clk_dump(void)
+{
+ dump_reg16(REG_DPLL, "REG_DPLL");
+ dump_reg16(CLKM_REG(CNTL_ARM_CLK), "CNTL_ARM_CLK");
+ dump_reg16(CLKM_REG(CNTL_CLK), "CNTL_CLK");
+ dump_reg16(CLKM_REG(CNTL_RST), "CNTL_RST");
+ dump_reg16(CLKM_REG(CNTL_ARM_DIV), "CNTL_ARM_DIV");
+}
+
+void calypso_pll_set(uint16_t inp)
+{
+ uint8_t mult = inp >> 8;
+ uint8_t div = inp & 0xff;
+ uint16_t reg = readw(REG_DPLL);
+
+ reg &= ~0x0fe0;
+ reg |= (div & 0x3) << DPLL_PLL_DIV_SHIFT;
+ reg |= (mult & 0x1f) << DPLL_PLL_MULT_SHIFT;
+ reg |= DPLL_PLL_ENABLE;
+
+ writew(reg, REG_DPLL);
+}
+
+void calypso_reset_set(enum calypso_rst calypso_rst, int active)
+{
+ uint8_t reg = readb(CLKM_REG(CNTL_RST));
+
+ if (active)
+ reg |= calypso_rst;
+ else
+ reg &= ~calypso_rst;
+
+ writeb(reg, CLKM_REG(CNTL_RST));
+}
+
+int calypso_reset_get(enum calypso_rst calypso_rst)
+{
+ uint8_t reg = readb(CLKM_REG(CNTL_RST));
+
+ if (reg & calypso_rst)
+ return 1;
+ else
+ return 0;
+}
+
+void calypso_clock_set(uint8_t vtcxo_div2, uint16_t inp, enum mclk_div mclk_div)
+{
+ uint16_t cntl_clock = readw(CLKM_REG(CNTL_CLK));
+ uint16_t cntl_arm_clk = readw(CLKM_REG(CNTL_ARM_CLK));
+
+ /* First set the vtcxo_div2 */
+ cntl_clock &= ~CLK_VCLKOUT_DIV2;
+ if (vtcxo_div2)
+ cntl_clock |= CLK_VTCXO_DIV2;
+ else
+ cntl_clock &= ~CLK_VTCXO_DIV2;
+ writew(cntl_clock, CLKM_REG(CNTL_CLK));
+
+ /* Then configure the MCLK divider */
+ cntl_arm_clk &= ~ARM_CLK_CLKIN_SEL0;
+ if (mclk_div & 0x80) {
+ mclk_div &= ~0x80;
+ cntl_arm_clk |= ARM_CLK_MCLK_DIV5;
+ } else
+ cntl_arm_clk &= ~ARM_CLK_MCLK_DIV5;
+ cntl_arm_clk &= ~(0x7 << ARM_CLK_MCLK_DIV_SHIFT);
+ cntl_arm_clk |= (mclk_div << ARM_CLK_MCLK_DIV_SHIFT);
+ writew(cntl_arm_clk, CLKM_REG(CNTL_ARM_CLK));
+
+ /* Then finally set the PLL */
+ calypso_pll_set(inp);
+}
+
+void calypso_mem_cfg(enum calypso_bank bank, uint8_t ws,
+ enum calypso_mem_width width, int we)
+{
+ writew((ws & 0x1f) | ((width & 3) << 5) | ((we & 1) << 7),
+ BASE_ADDR_MEMIF + bank);
+}
+
+void calypso_bootrom(int enable)
+{
+ uint16_t conf = readw(MEMIF_REG(EXTRA_CONF));
+
+ conf |= (3 << 8);
+
+ if (enable)
+ conf &= ~(1 << 9);
+
+ writew(conf, MEMIF_REG(EXTRA_CONF));
+}
+
+void calypso_debugunit(int enable)
+{
+ uint16_t conf = readw(MEMIF_REG(EXTRA_CONF));
+
+ if (enable)
+ conf &= ~(1 << 11);
+ else
+ conf |= (1 << 11);
+
+ writew(conf, MEMIF_REG(EXTRA_CONF));
+}
+
+#define REG_RHEA_CNTL 0xfffff900
+#define REG_API_CNTL 0xfffff902
+#define REG_ARM_RHEA 0xfffff904
+
+void calypso_rhea_cfg(uint8_t fac0, uint8_t fac1, uint8_t timeout,
+ uint8_t ws_h, uint8_t ws_l, uint8_t w_en0, uint8_t w_en1)
+{
+ writew(fac0 | (fac1 << 4) | (timeout << 8), REG_RHEA_CNTL);
+ writew(ws_h | (ws_l << 5), REG_API_CNTL);
+ writew(w_en0 | (w_en1 << 1), REG_ARM_RHEA);
+}
diff --git a/src/target/firmware/calypso/dma.c b/src/target/firmware/calypso/dma.c
new file mode 100644
index 00000000..35c5be82
--- /dev/null
+++ b/src/target/firmware/calypso/dma.c
@@ -0,0 +1,44 @@
+/* Driver for Calypso DMA controller */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <memory.h>
+
+#define BASE_ADDR_DMA 0xfffffc00
+
+enum dma_reg {
+ CONTROLLER_CONF = 0x00,
+ ALLOC_CONFIG = 0x02,
+};
+#define DMA_REG(m) (BASE_ADDR_DMA + (m))
+
+#define DMA_RAD(x) DMA_REG((x)*0x10 + 0x0)
+#define DMA_RDPATH(x) DMA_REG((x)*0x10 + 0x2)
+#define DMA_AAD(x) DMA_REG((x)*0x10 + 0x4)
+#define DMA_ALGTH(x) DMA_REG((x)*0x10 + 0x6)
+#define DMA_CTRL(x) DMA_REG((x)*0x10 + 0x8)
+#define DMA_CUR_OFF_API(x) DMA_REG((x)*0x10 + 0xa)
+
+void dma_init(void)
+{
+ /* DMA 1 (RIF Tx), 2 (RIF Rx) allocated to DSP, all others to ARM */
+ writew(0x000c, DMA_REG(ALLOC_CONFIG));
+}
diff --git a/src/target/firmware/calypso/dsp.c b/src/target/firmware/calypso/dsp.c
new file mode 100644
index 00000000..1daecb2d
--- /dev/null
+++ b/src/target/firmware/calypso/dsp.c
@@ -0,0 +1,693 @@
+#define DEBUG
+/* Driver for the Calypso integrated DSP */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <delay.h>
+#include <memory.h>
+#include <calypso/clock.h>
+#include <calypso/dsp.h>
+#include <calypso/dsp_api.h>
+#include <calypso/tpu.h>
+
+#include <abb/twl3025.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+
+
+#define REG_API_CONTROL 0xfffe0000
+#define APIC_R_SMODE_HOM (1 << 1) /* API is configured in HOM mode */
+#define APIC_R_HINT (1 << 3) /* Host processor interrupt (DSP->MCU) */
+#define APIC_W_DSPINT (1 << 2) /* ARM issues interrupt to DSP */
+
+#define REG_API_WS 0xfffff902 /* Number of wait states for ARM access to API memory */
+#define REG_ARM_RHEA_CTL 0xfffff904 /* Write buffer bypassing */
+#define REG_EXT_RHEA_CTL 0xfffff906 /* Some timeout */
+
+#define API_SIZE 0x2000U /* in words */
+
+#define BASE_API_RAM 0xffd00000 /* Base address of API RAM from ARM point of view */
+
+#define DSP_BASE_API 0x0800 /* Base address of API RAM for DSP */
+#define DSP_BASE_API_MIRROR 0xe000 /* Base address of API RAM for DSP (API boot mirror) */
+#define DSP_START 0x7000 /* DSP Start address */
+
+/* Boot loader */
+#define BL_CMD_STATUS (BASE_API_RAM + 0x0ffe) /* Status / Command var */
+#define BL_ADDR_LO (BASE_API_RAM + 0x0ffc) /* Address (16 lsbs) */
+#define BL_ADDR_HI (BASE_API_RAM + 0x0ff8) /* Address (ext page bits) */
+#define BL_SIZE (BASE_API_RAM + 0x0ffa) /* Size */
+
+#define BL_MAX_BLOCK_SIZE 0x7F0 /* Maximum size of copied block */
+
+ /* Possible values for the download status */
+#define BL_STATUS_NA 0
+#define BL_STATUS_IDLE 1
+#define BL_CMD_COPY_BLOCK 2
+#define BL_CMD_COPY_MODE 4
+
+#define BL_MODE_PROG_WRITE 0
+#define BL_MODE_DATA_WRITE 1
+#define BL_MODE_PROG_READ 2
+#define BL_MODE_DATA_READ 3
+#define BL_MODE_PROM_READ 4
+#define BL_MODE_DROM_READ 5
+
+
+struct dsp_section {
+ uint32_t addr; /* addr for DSP */
+ uint32_t size; /* size in words */
+ const uint16_t *data;
+};
+
+#include "dsp_params.c"
+#include "dsp_bootcode.c"
+#include "dsp_dumpcode.c"
+
+struct dsp_api dsp_api = {
+ .ndb = (T_NDB_MCU_DSP *) BASE_API_NDB,
+ .db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0,
+ .db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0,
+ .param = (T_PARAM_MCU_DSP *) BASE_API_PARAM,
+ .r_page = 0,
+ .w_page = 0,
+};
+
+
+void dsp_dump_version(void)
+{
+ printf("DSP Download Status: 0x%04x\n", readw(BL_CMD_STATUS));
+ printf("DSP API Version: 0x%04x 0x%04x\n",
+ dsp_api.ndb->d_version_number1, dsp_api.ndb->d_version_number2);
+}
+
+static void dsp_bl_wait_ready(void)
+{
+ while (readw(BL_CMD_STATUS) != BL_STATUS_IDLE);
+}
+
+static void dsp_bl_start_at(uint16_t addr)
+{
+ writew(0, BL_ADDR_HI);
+ writew(addr, BL_ADDR_LO);
+ writew(0, BL_SIZE);
+ writew(BL_CMD_COPY_BLOCK, BL_CMD_STATUS);
+}
+
+static int dsp_bl_upload_sections(const struct dsp_section *sec)
+{
+ /* Make sure the bootloader is ready */
+ dsp_bl_wait_ready();
+
+ /* Set mode */
+ writew(BL_MODE_DATA_WRITE, BASE_API_RAM);
+ writew(BL_CMD_COPY_MODE, BL_CMD_STATUS);
+ dsp_bl_wait_ready();
+
+ /* Scan all sections */
+ for (; sec->data; sec++) {
+ volatile uint16_t *api = (volatile uint16_t *)BASE_API_RAM;
+ unsigned int i;
+
+ if (sec->size > BL_MAX_BLOCK_SIZE)
+ return -1; /* not supported for now */
+
+ /* Copy data to API */
+ for (i=0; i<sec->size; i++)
+ api[i] = sec->data[i];
+
+ /* Issue DRAM write */
+ writew(sec->addr >> 16, BL_ADDR_HI);
+ writew(sec->addr & 0xffff, BL_ADDR_LO);
+ writew(sec->size, BL_SIZE);
+ writew(BL_CMD_COPY_BLOCK, BL_CMD_STATUS);
+
+ /* Wait for completion */
+ dsp_bl_wait_ready();
+ }
+
+ return 0;
+}
+
+static int dsp_upload_sections_api(const struct dsp_section *sec, uint16_t dsp_base_api)
+{
+ for (; sec->data; sec++) {
+ unsigned int i;
+ volatile uint16_t *dptr;
+
+ if (sec->addr & ~((1<<16)-1)) /* 64k max addr */
+ return -1;
+ if (sec->addr < dsp_base_api)
+ return -1;
+ if ((sec->addr + sec->size) > (dsp_base_api + API_SIZE))
+ return -1;
+
+ dptr = (volatile uint16_t *)(BASE_API_RAM + ((sec->addr - dsp_base_api) * sizeof(uint16_t)));
+ for (i=0; i<sec->size; i++)
+ *dptr++ = sec->data[i];
+ }
+
+ /* FIXME need eioio or wb ? */
+
+ return 0;
+}
+
+static void dsp_pre_boot(const struct dsp_section *bootcode)
+{
+ dputs("Assert DSP into Reset\n");
+ calypso_reset_set(RESET_DSP, 1);
+
+ if (bootcode) {
+ dputs("Loading initial DSP bootcode (API boot mode)\n");
+ dsp_upload_sections_api(bootcode, DSP_BASE_API_MIRROR);
+
+ writew(BL_STATUS_NA, BL_CMD_STATUS);
+ } else
+ delay_ms(10);
+
+ dputs("Releasing DSP from Reset\n");
+ calypso_reset_set(RESET_DSP, 0);
+
+ /* Wait 10 us */
+ delay_ms(100);
+
+ dsp_bl_wait_ready();
+}
+
+static void dsp_set_params(int16_t *param_tab, int param_size)
+{
+ int i;
+ int16_t *param_ptr = (int16_t *) BASE_API_PARAM;
+
+ /* Start DSP up to bootloader */
+ dsp_pre_boot(dsp_bootcode);
+
+ /* FIXME: Implement Patch download, if any */
+
+ dputs("Setting some dsp_api.ndb values\n");
+ dsp_api.ndb->d_background_enable = 0;
+ dsp_api.ndb->d_background_abort = 0;
+ dsp_api.ndb->d_background_state = 0;
+ dsp_api.ndb->d_debug_ptr = 0x0074;
+ dsp_api.ndb->d_debug_bk = 0x0001;
+ dsp_api.ndb->d_pll_config = 0x154; //C_PLL_CONFIG;
+ dsp_api.ndb->p_debug_buffer = 0x17ff; //C_DEBUG_BUFFER_ADD;
+ dsp_api.ndb->d_debug_buffer_size = 7; //C_DEBUG_BUFFER_SIZE;
+ dsp_api.ndb->d_debug_trace_type = 0; //C_DEBUG_TRACE_TYPE;
+ dsp_api.ndb->d_dsp_state = 3; //C_DSP_IDLE3;
+ dsp_api.ndb->d_audio_gain_ul = 0;
+ dsp_api.ndb->d_audio_gain_dl = 0;
+ dsp_api.ndb->d_es_level_api = 0x5213;
+ dsp_api.ndb->d_mu_api = 0x5000;
+
+ dputs("Setting API NDB parameters\n");
+ for (i = 0; i < param_size; i ++)
+ *param_ptr++ = param_tab[i];
+
+ dsp_dump_version();
+
+ dputs("Finishing download phase\n");
+ dsp_bl_start_at(DSP_START);
+
+ dsp_dump_version();
+}
+
+void dsp_api_memset(uint16_t *ptr, int octets)
+{
+ uint16_t i;
+ for (i = 0; i < octets / sizeof(uint16_t); i++)
+ *ptr++ = 0;
+}
+
+/* memcpy from RAM to DSP API, 16 bits by 16 bits. If odd byte count, last word will
+ * be zero filled */
+void dsp_memcpy_to_api(volatile uint16_t *dsp_buf, const uint8_t *mcu_buf, int n, int be)
+{
+ int odd, i;
+
+ odd = n & 1;
+ n >>= 1;
+
+ if (be) {
+ for (i=0; i<n; i++) {
+ uint16_t w;
+ w = *(mcu_buf++) << 8;
+ w |= *(mcu_buf++);
+ *(dsp_buf++) = w;
+ }
+ if (odd)
+ *dsp_buf = *mcu_buf << 8;
+ } else {
+ for (i=0; i<n; i++) {
+ uint16_t w;
+ w = *(mcu_buf++);
+ w |= *(mcu_buf++) << 8;
+ *(dsp_buf++) = w;
+ }
+ if (odd)
+ *dsp_buf = *mcu_buf;
+ }
+}
+
+/* memcpy from DSP API to RAM, accessing API 16 bits word at a time */
+void dsp_memcpy_from_api(uint8_t *mcu_buf, const volatile uint16_t *dsp_buf, int n, int be)
+{
+ int odd, i;
+
+ odd = n & 1;
+ n >>= 1;
+
+ if (be) {
+ for (i=0; i<n; i++) {
+ uint16_t w = *(dsp_buf++);
+ *(mcu_buf++) = w >> 8;
+ *(mcu_buf++) = w;
+ }
+ if (odd)
+ *mcu_buf = *(dsp_buf++) >> 8;
+ } else {
+ for (i=0; i<n; i++) {
+ uint16_t w = *(dsp_buf++);
+ *(mcu_buf++) = w;
+ *(mcu_buf++) = w >> 8;
+ }
+ if (odd)
+ *mcu_buf = *(dsp_buf++);
+ }
+}
+
+static void dsp_audio_init(void)
+{
+ T_NDB_MCU_DSP *ndb = dsp_api.ndb;
+ uint8_t i;
+
+ ndb->d_vbctrl1 = ABB_VAL_T(VBCTRL1, 0x00B); /* VULSWITCH=0, VDLAUX=1, VDLEAR=1 */
+ ndb->d_vbctrl2 = ABB_VAL_T(VBCTRL2, 0x000); /* MICBIASEL=0, VDLHSO=0, MICAUX=0 */
+
+ /*
+ * TODO: the following two settings are used to control
+ * the volume and uplink/downlink/sidetone gain. Make them
+ * adjustable by the user.
+ */
+
+ ndb->d_vbuctrl = ABB_VAL_T(VBUCTRL, 0x009); /* Uplink gain amp 3dB, Sidetone gain -5dB */
+ ndb->d_vbdctrl = ABB_VAL_T(VBDCTRL, 0x066); /* Downlink gain amp 0dB, Volume control -6 dB */
+
+ ndb->d_toneskb_init = 0; /* MCU/DSP audio task com. register */
+ ndb->d_toneskb_status = 0; /* MCU/DSP audio task com. register */
+
+ ndb->d_shiftul = 0x100;
+ ndb->d_shiftdl = 0x100;
+
+ ndb->d_melo_osc_used = 0;
+ ndb->d_melo_osc_active = 0;
+
+#define SC_END_OSCILLATOR_MASK 0xfffe
+
+ ndb->a_melo_note0[0] = SC_END_OSCILLATOR_MASK;
+ ndb->a_melo_note1[0] = SC_END_OSCILLATOR_MASK;
+ ndb->a_melo_note2[0] = SC_END_OSCILLATOR_MASK;
+ ndb->a_melo_note3[0] = SC_END_OSCILLATOR_MASK;
+ ndb->a_melo_note4[0] = SC_END_OSCILLATOR_MASK;
+ ndb->a_melo_note5[0] = SC_END_OSCILLATOR_MASK;
+ ndb->a_melo_note6[0] = SC_END_OSCILLATOR_MASK;
+ ndb->a_melo_note7[0] = SC_END_OSCILLATOR_MASK;
+
+#define MAX_FIR_COEF 31
+
+ /* Initialize the FIR as an all band pass */
+ dsp_api.param->a_fir31_downlink[0] = 0x4000;
+ dsp_api.param->a_fir31_uplink[0] = 0x4000;
+ for (i = 1; i < MAX_FIR_COEF; i++)
+ {
+ dsp_api.param->a_fir31_downlink[i] = 0;
+ dsp_api.param->a_fir31_uplink[i] = 0;
+ }
+
+#define B_GSM_ONLY ((1L << 13) | (1L << 11)) /* GSM normal mode */
+#define B_BT_CORDLESS (1L << 12) /* Bluetooth cordless mode */
+#define B_BT_HEADSET (1L << 14) /* Bluetooth headset mode */
+
+ /* Bit set by the MCU to close the loop between the audio UL and DL path. */
+ /* This features is used to find the FIR coefficient. */
+#define B_FIR_LOOP (1L << 1)
+
+ /* Reset the FIR loopback and the audio mode */
+ ndb->d_audio_init &= ~(B_FIR_LOOP | B_GSM_ONLY | B_BT_HEADSET | B_BT_CORDLESS);
+
+ /* Set the GSM mode */
+ ndb->d_audio_init |= (B_GSM_ONLY);
+
+ ndb->d_aec_ctrl = 0;
+
+ /* DSP background task through pending task queue */
+ dsp_api.param->d_gsm_bgd_mgt = 0;
+
+ ndb->d_audio_compressor_ctrl = 0x0401;
+
+#define NO_MELODY_SELECTED (0)
+
+ ndb->d_melody_selection = NO_MELODY_SELECTED;
+}
+
+static void dsp_ndb_init(void)
+{
+ T_NDB_MCU_DSP *ndb = dsp_api.ndb;
+ uint8_t i;
+
+ #define APCDEL_DOWN (2+0) // minimum value: 2
+ #define APCDEL_UP (6+3+1) // minimum value: 6
+
+ /* load APC ramp: set to "no ramp" so that there will be no output if
+ * not properly initialised at some other place. */
+ for (i = 0; i < 16; i++)
+ dsp_api.ndb->a_ramp[i] = ABB_VAL(APCRAM, ABB_RAMP_VAL(0, 0));
+
+ /* Iota registers values will be programmed at 1st DSP communication interrupt */
+
+ /* Enable f_tx delay of 400000 cyc DEBUG */
+ ndb->d_debug1 = ABB_VAL_T(0, 0x000);
+ ndb->d_afcctladd= ABB_VAL_T(AFCCTLADD, 0x000); // Value at reset
+ ndb->d_vbuctrl = ABB_VAL_T(VBUCTRL, 0x0C9); // Uplink gain amp 0dB, Sidetone gain to mute
+ ndb->d_vbdctrl = ABB_VAL_T(VBDCTRL, 0x006); // Downlink gain amp 0dB, Volume control 0 dB
+ ndb->d_bbctrl = ABB_VAL_T(BBCTRL, 0x2C1); // value at reset
+ ndb->d_bulgcal = ABB_VAL_T(BULGCAL, 0x000); // value at reset
+ ndb->d_apcoff = ABB_VAL_T(APCOFF, 0x040); // value at reset
+ ndb->d_bulioff = ABB_VAL_T(BULIOFF, 0x0FF); // value at reset
+ ndb->d_bulqoff = ABB_VAL_T(BULQOFF, 0x0FF); // value at reset
+ ndb->d_dai_onoff= ABB_VAL_T(APCOFF, 0x000); // value at reset
+ ndb->d_auxdac = ABB_VAL_T(AUXDAC, 0x000); // value at reset
+ ndb->d_vbctrl1 = ABB_VAL_T(VBCTRL1, 0x00B); // VULSWITCH=0, VDLAUX=1, VDLEAR=1.
+ ndb->d_vbctrl2 = ABB_VAL_T(VBCTRL2, 0x000); // MICBIASEL=0, VDLHSO=0, MICAUX=0
+
+ /* APCDEL will be initialized on rach only */
+ ndb->d_apcdel1 = ABB_VAL_T(APCDEL1, ((APCDEL_DOWN-2) << 5) | (APCDEL_UP-6));
+ ndb->d_apcdel2 = ABB_VAL_T(APCDEL2, 0x000);
+
+ ndb->d_fb_mode = 1; /* mode 1 FCCH burst detection */
+ ndb->d_fb_det = 0; /* we have not yet detected a FB */
+ ndb->a_cd[0] = (1<<B_FIRE1); /* CCCH/SACCH downlink */
+ ndb->a_dd_0[0] = 0;
+ ndb->a_dd_0[2] = 0xffff;
+ ndb->a_dd_1[0] = 0;
+ ndb->a_dd_1[2] = 0xffff;
+ ndb->a_du_0[0] = 0;
+ ndb->a_du_0[2] = 0xffff;
+ ndb->a_du_1[0] = 0;
+ ndb->a_du_1[2] = 0xffff;
+ ndb->a_fd[0] = (1<<B_FIRE1);
+ ndb->a_fd[2] = 0xffff;
+ ndb->d_a5mode = 0;
+ ndb->d_tch_mode = 0x0800; /* Set ABB model to Iota */
+
+ #define GUARD_BITS 8 // 11 or 9 for TSM30, 7 for Freerunner
+ ndb->d_tch_mode |= (((GUARD_BITS - 4) & 0x000F) << 7); //Bit 7..10: guard bits
+
+ ndb->a_sch26[0] = (1<<B_SCH_CRC);
+
+ /* Interrupt RIF transmit if FIFO <= threshold with threshold == 0 */
+ /* MCM = 1, XRST = 0, CLKX_AUTO=1, TXM=1, NCLK_EN=1, NCLK13_EN=1,
+ * THRESHOLD = 0, DIV_CLK = 0 (13MHz) */
+ ndb->d_spcx_rif = 0x179;
+
+ /* Init audio related parameters */
+ dsp_audio_init();
+}
+
+static void dsp_db_init(void)
+{
+ dsp_api_memset((uint16_t *)BASE_API_W_PAGE_0, sizeof(T_DB_MCU_TO_DSP));
+ dsp_api_memset((uint16_t *)BASE_API_W_PAGE_1, sizeof(T_DB_MCU_TO_DSP));
+ dsp_api_memset((uint16_t *)BASE_API_R_PAGE_0, sizeof(T_DB_DSP_TO_MCU));
+ dsp_api_memset((uint16_t *)BASE_API_R_PAGE_1, sizeof(T_DB_DSP_TO_MCU));
+}
+
+void dsp_power_on(void)
+{
+ /* probably a good idea to initialize the whole API area to a known value */
+ dsp_api_memset((uint16_t *)BASE_API_RAM, API_SIZE * 2); // size is in words
+
+ dsp_set_params((int16_t *)&dsp_params, sizeof(dsp_params)/2);
+ dsp_ndb_init();
+ dsp_db_init();
+ dsp_api.frame_ctr = 0;
+ dsp_api.r_page = dsp_api.w_page = dsp_api.r_page_used = 0;
+}
+
+/* test for frequency burst detection */
+#define REG_INT_STAT 0xffff1004
+static void wait_for_frame_irq(void)
+{
+ //puts("Waiting for Frame Interrupt");
+ //while (readb(REG_INT_STAT) & 1)
+ while (readb((void *)0xffff1000) & (1<<4))
+ ;// putchar('.');
+ //puts("Done!\n");
+}
+
+void dsp_end_scenario(void)
+{
+ /* FIXME: we don't yet deal with the MISC_TASK */
+
+ /* End the DSP Scenario */
+ dsp_api.ndb->d_dsp_page = B_GSM_TASK | dsp_api.w_page;
+ dsp_api.w_page ^= 1;
+
+ /* Tell TPU to generate a FRAME interrupt to the DSP */
+ tpu_dsp_frameirq_enable();
+ tpu_frame_irq_en(1, 1);
+}
+
+void dsp_load_rx_task(uint16_t task, uint8_t burst_id, uint8_t tsc)
+{
+ dsp_api.db_w->d_task_d = task;
+ dsp_api.db_w->d_burst_d = burst_id;
+ dsp_api.db_w->d_ctrl_system |= tsc & 0x7;
+}
+
+void dsp_load_tx_task(uint16_t task, uint8_t burst_id, uint8_t tsc)
+{
+ dsp_api.db_w->d_task_u = task;
+ dsp_api.db_w->d_burst_u = burst_id;
+ dsp_api.db_w->d_ctrl_system |= tsc & 0x7;
+}
+
+/* no AMR yet */
+void dsp_load_tch_param(struct gsm_time *next_time,
+ uint8_t chan_mode, uint8_t chan_type, uint8_t chan_sub,
+ uint8_t tch_loop, uint8_t sync_tch, uint8_t tn)
+{
+ uint16_t d_ctrl_tch;
+ uint16_t fn, a5fn0, a5fn1;
+
+ /* d_ctrl_tch
+ ----------
+ bit [0..3] -> b_chan_mode
+ bit [4..7] -> b_chan_type
+ bit [8] -> b_sync_tch_ul
+ bit [9] -> b_sync_tch_dl
+ bit [10] -> b_stop_tch_ul
+ bit [11] -> b_stop_tch_dl
+ bit [12..14] -> b_tch_loop
+ bit [15] -> b_subchannel */
+ d_ctrl_tch = (chan_mode << B_CHAN_MODE) |
+ (chan_type << B_CHAN_TYPE) |
+ (chan_sub << B_SUBCHANNEL) |
+ (sync_tch << B_SYNC_TCH_UL) |
+ (sync_tch << B_SYNC_TCH_DL) |
+ (tch_loop << B_TCH_LOOP);
+
+ /* used for ciphering and TCH traffic */
+
+ /* d_fn
+ ----
+
+ for TCH_F:
+ bit [0..7] -> b_fn_report = (fn - (tn * 13) + 104) % 104)
+ bit [8..15] -> b_fn_sid = (fn % 104)
+
+ for TCH_H:
+ tn_report = (tn & ~1) | subchannel
+ bit [0..7] -> b_fn_report = (fn - tn_report * 13) + 104) % 104)
+ bit [8..15] -> b_fn_sid = (fn % 104)
+
+ for other: irrelevant
+ */
+
+ if (chan_type == TCH_F) {
+ fn = ((next_time->fn - (tn * 13) + 104) % 104) |
+ ((next_time->fn % 104) << 8);
+ } else if (chan_type == TCH_H) {
+ uint8_t tn_report = (tn & ~1) | chan_sub;
+ fn = ((next_time->fn - (tn_report * 13) + 104) % 104) |
+ ((next_time->fn % 104) << 8);
+ } else {
+ /* irrelevant */
+ fn = 0;
+ }
+
+ /* a_a5fn
+ ------
+ byte[0] bit [0..4] -> T2
+ byte[0] bit [5..10] -> T3
+ byte[1] bit [0..10] -> T1 */
+
+ a5fn0 = ((uint16_t)next_time->t3 << 5) |
+ (uint16_t)next_time->t2;
+ a5fn1 = (uint16_t)next_time->t1;
+
+ dsp_api.db_w->d_fn = fn; /* Fn_sid & Fn_report */
+ dsp_api.db_w->a_a5fn[0] = a5fn0; /* ciphering FN part 1 */
+ dsp_api.db_w->a_a5fn[1] = a5fn1; /* ciphering FN part 2 */
+ dsp_api.db_w->d_ctrl_tch = d_ctrl_tch; /* Channel config. */
+}
+
+void dsp_load_ciph_param(int mode, uint8_t *key)
+{
+ dsp_api.ndb->d_a5mode = mode;
+
+ if (!mode || !key)
+ return;
+
+ /* key is expected in the same format as in RSL
+ * Encryption information IE. So we need to load the
+ * bytes backward in A5 unit */
+ dsp_api.ndb->a_kc[0] = (uint16_t)key[7] | ((uint16_t)key[6] << 8);
+ dsp_api.ndb->a_kc[1] = (uint16_t)key[5] | ((uint16_t)key[4] << 8);
+ dsp_api.ndb->a_kc[2] = (uint16_t)key[3] | ((uint16_t)key[2] << 8);
+ dsp_api.ndb->a_kc[3] = (uint16_t)key[1] | ((uint16_t)key[0] << 8);
+}
+
+#define SC_CHKSUM_VER (BASE_API_W_PAGE_0 + (2 * (0x08DB - 0x800)))
+static void dsp_dump_csum(void)
+{
+ printf("dsp page : %u\n", dsp_api.ndb->d_dsp_page);
+ printf("dsp code version : 0x%04x\n", dsp_api.db_r->a_pm[0]);
+ printf("dsp checksum : 0x%04x\n", dsp_api.db_r->a_pm[1]);
+ printf("dsp patch version : 0x%04x\n", readw(SC_CHKSUM_VER));
+}
+
+void dsp_checksum_task(void)
+{
+ dsp_dump_csum();
+ dsp_api.db_w->d_task_md = CHECKSUM_DSP_TASK;
+ dsp_api.ndb->d_fb_mode = 1;
+
+ dsp_end_scenario();
+
+ wait_for_frame_irq();
+
+ dsp_dump_csum();
+}
+
+#define L1D_AUXAPC 0x0012
+#define L1D_APCRAM 0x0014
+
+void dsp_load_apc_dac(uint16_t apc)
+{
+ dsp_api.db_w->d_power_ctl = (apc << 6) | L1D_AUXAPC;
+}
+
+
+static void _dsp_dump_range(uint32_t addr, uint32_t size, int mode)
+{
+ uint32_t bs;
+
+ /* Mode selection */
+ writew(mode, BASE_API_RAM);
+ writew(BL_CMD_COPY_MODE, BL_CMD_STATUS);
+ dsp_bl_wait_ready();
+
+ /* Block by block dump */
+ while (size) {
+ volatile uint16_t *api = (volatile uint16_t *)BASE_API_RAM;
+
+ bs = (size > BL_MAX_BLOCK_SIZE) ? BL_MAX_BLOCK_SIZE : size;
+ size -= bs;
+
+ writew(addr >> 16, BL_ADDR_HI);
+ writew(addr & 0xffff, BL_ADDR_LO);
+ writew(bs, BL_SIZE);
+ writew(BL_CMD_COPY_BLOCK, BL_CMD_STATUS);
+
+ dsp_bl_wait_ready();
+
+ while (bs--) {
+ /* FIXME workaround: small delay to prevent overflowing
+ * the sercomm buffer */
+ delay_ms(2);
+ if ((addr&15)==0)
+ printf("%05x : ", addr);
+ printf("%04hx%c", *api++, ((addr&15)==15)?'\n':' ');
+ addr++;
+ }
+ };
+ puts("\n");
+}
+
+void dsp_dump(void)
+{
+ static const struct {
+ const char *name;
+ uint32_t addr;
+ uint32_t size;
+ int mode;
+ } dr[] = {
+ { "Registers", 0x00000, 0x0060, BL_MODE_DATA_READ },
+ { "DROM", 0x09000, 0x5000, BL_MODE_DROM_READ },
+ { "PDROM", 0x0e000, 0x2000, BL_MODE_DROM_READ },
+ { "PROM0", 0x07000, 0x7000, BL_MODE_PROM_READ },
+ { "PROM1", 0x18000, 0x8000, BL_MODE_PROM_READ },
+ { "PROM2", 0x28000, 0x8000, BL_MODE_PROM_READ },
+ { "PROM3", 0x38000, 0x2000, BL_MODE_PROM_READ },
+ { NULL, 0, 0, -1 }
+ };
+
+ int i;
+
+ /* Start DSP up to bootloader */
+ dsp_pre_boot(dsp_bootcode);
+
+ /* Load and execute our dump code in the DSP */
+ dsp_upload_sections_api(dsp_dumpcode, DSP_BASE_API);
+ dsp_bl_start_at(DSP_DUMPCODE_START);
+
+ /* our dump code actually simulates the boot loader
+ * but with added read commands */
+ dsp_bl_wait_ready();
+
+ /* Test the 'version' command */
+ writew(0xffff, BL_CMD_STATUS);
+ dsp_bl_wait_ready();
+ printf("DSP bootloader version 0x%04x\n", readw(BASE_API_RAM));
+
+ /* Dump each range */
+ for (i=0; dr[i].name; i++) {
+ printf("DSP dump: %s [%05x-%05x]\n", dr[i].name,
+ dr[i].addr, dr[i].addr+dr[i].size-1);
+ _dsp_dump_range(dr[i].addr, dr[i].size, dr[i].mode);
+ }
+}
+
diff --git a/src/target/firmware/calypso/dsp_bootcode.c b/src/target/firmware/calypso/dsp_bootcode.c
new file mode 100644
index 00000000..2db46568
--- /dev/null
+++ b/src/target/firmware/calypso/dsp_bootcode.c
@@ -0,0 +1,9 @@
+/* Calypso integrated DSP boot code */
+
+#define _SA_DECL (const uint16_t *)&(const uint16_t [])
+
+/* We don't really need any DSP boot code, it happily works with its own ROM */
+static const struct dsp_section *dsp_bootcode = NULL;
+
+#undef _SA_DECL
+
diff --git a/src/target/firmware/calypso/dsp_dumpcode.c b/src/target/firmware/calypso/dsp_dumpcode.c
new file mode 100644
index 00000000..265a1c12
--- /dev/null
+++ b/src/target/firmware/calypso/dsp_dumpcode.c
@@ -0,0 +1,45 @@
+/* Generated from src/target_dsp/calypso/dsp_dump.bin */
+
+#define _SA_DECL (const uint16_t *)&(const uint16_t [])
+
+static const struct dsp_section dsp_dumpcode[] = {
+ {
+ .addr = 0x1000,
+ .size = 0x005b,
+ .data = _SA_DECL {
+ 0x69f8, 0x0029, 0x0002, 0xea1f,
+ 0x7718, 0x1100, 0x7714, 0x0000,
+ 0x7712, 0x0800, 0x767f, 0x0001,
+ 0x607f, 0xffff, 0xf820, 0x1014,
+ 0xf273, 0x1008, 0x7682, 0x0100,
+ 0x607f, 0x0004, 0xf820, 0x101c,
+ 0xf273, 0x1008, 0x7214, 0x0800,
+ 0x607f, 0x0002, 0xf820, 0x100c,
+ 0x127e, 0x8813, 0x3c7c, 0x137d,
+ 0x8911, 0xf84c, 0x1028, 0xf4e2,
+ 0x7715, 0x0014, 0x963d, 0xfa30,
+ 0x104b, 0x6d89, 0x963f, 0xfa30,
+ 0x103f, 0x963e, 0xf495, 0xf830,
+ 0x103a, 0x47f8, 0x0011, 0x7f92,
+ 0xf073, 0x1008, 0x47f8, 0x0011,
+ 0x7e92, 0xf073, 0x1008, 0xf830,
+ 0x1046, 0x47f8, 0x0011, 0xe589,
+ 0xf073, 0x1008, 0x47f8, 0x0011,
+ 0xe598, 0xf073, 0x1008, 0x4911,
+ 0x891a, 0xf830, 0x1055, 0xf072,
+ 0x1052, 0xf074, 0x7213, 0xf073,
+ 0x1008, 0xf072, 0x1058, 0xf074,
+ 0xe4b8, 0xf073, 0x1008,
+ },
+ },
+ { /* Guard */
+ .addr = 0,
+ .size = 0,
+ .data = NULL,
+ },
+};
+
+#define DSP_DUMPCODE_START 0x1000
+
+#undef _SA_DECL
+
diff --git a/src/target/firmware/calypso/dsp_params.c b/src/target/firmware/calypso/dsp_params.c
new file mode 100644
index 00000000..e08b46e6
--- /dev/null
+++ b/src/target/firmware/calypso/dsp_params.c
@@ -0,0 +1,94 @@
+/* Values from an actual phone firmware that uses the 3306 DSP ROM code version */
+static T_PARAM_MCU_DSP dsp_params = {
+ .d_transfer_rate = 0x6666,
+ /* Latencies */
+ .d_lat_mcu_bridge = 15,
+ .d_lat_mcu_hom2sam = 12,
+ .d_lat_mcu_bef_fast_access = 5,
+ .d_lat_dsp_after_sam = 4,
+ /* DSP Start Address */
+ .d_gprs_install_address = 0x7002, /* needs to be set by patch or manually */
+ .d_misc_config = 1,
+ .d_cn_sw_workaround = 0xE,
+ .d_hole2_param = { 0, 0, 0, 0 },
+ /* Frequency Burst */
+ .d_fb_margin_beg = 24,
+ .d_fb_margin_end = 22,
+ .d_nsubb_idle = 296,
+ .d_nsubb_dedic = 30,
+ .d_fb_thr_det_iacq = 0x3333,
+ .d_fb_thr_det_track = 0x28f6,
+ /* Demodulation */
+ .d_dc_off_thres = 0x7fff,
+ .d_dummy_thres = 17408,
+ .d_dem_pond_gewl = 26624,
+ .d_dem_pond_red = 20152,
+ /* TCH Full Speech */
+ .d_maccthresh1 = 7872,
+ .d_mldt = -4,
+ .d_maccthresh = 7872,
+ .d_gu = 5772,
+ .d_go = 7872,
+ .d_attmax = 53,
+ .d_sm = -892,
+ .d_b = 208,
+ /* V.42 bis */
+ .d_v42b_switch_hyst = 16,
+ .d_v42b_switch_min = 64,
+ .d_v42b_switch_max = 250,
+ .d_v42b_reset_delay = 10,
+ /* TCH Half Speech */
+ .d_ldT_hr = -5,
+ .d_maccthresh_hr = 6500,
+ .d_maccthresh1_hr = 6500,
+ .d_gu_hr = 2620,
+ .d_go_hr = 3700,
+ .d_b_hr = 182,
+ .d_sm_hr = -1608,
+ .d_attmax_hr = 53,
+ /* TCH Enhanced FR Speech */
+ .c_mldt_efr = -4,
+ .c_maccthresh_efr = 8000,
+ .c_maccthresh1_efr = 8000,
+ .c_gu_efr = 4522,
+ .c_go_efr = 6500,
+ .c_b_efr = 174,
+ .c_sm_efr = -878,
+ .c_attmax_efr = 53,
+ /* CHED TCH Full Speech */
+ .d_sd_min_thr_tchfs = 15,
+ .d_ma_min_thr_tchfs = 738,
+ .d_md_max_thr_tchfs = 1700,
+ .d_md1_max_thr_tchfs = 99,
+ /* CHED TCH Half Speech */
+ .d_sd_min_thr_tchhs = 37,
+ .d_ma_min_thr_tchhs = 344,
+ .d_sd_av_thr_tchhs = 1845,
+ .d_md_max_thr_tchhs = 2175,
+ .d_md1_max_thr_tchhs = 138,
+ /* CHED TCH/F EFR Speech */
+ .d_sd_min_thr_tchefs = 15,
+ .d_ma_min_thr_tchefs = 738,
+ .d_md_max_thr_tchefs = 0x4ce,
+ .d_md1_max_thr_tchefs = 0x63,
+ /* */
+ .d_wed_fil_ini = 0x122a,
+ .d_wed_fil_tc = 0x7c00,
+ .d_x_min = 0xf,
+ .d_x_max = 0x17,
+ .d_slope = 0x87,
+ .d_y_min = 0x2bf,
+ .d_y_max = 0x99c,
+ .d_wed_diff_threshold = 0x196,
+ .d_mabfi_min_thr_tchhs = 0x14c8,
+ /* FACCH module */
+ .d_facch_thr = 0,
+ /* IDS module */
+ .d_max_ovsp_ul = 8,
+ .d_sync_thres = 0x3f50,
+ .d_idle_thres = 0x4000,
+ .d_m1_thres = 5,
+ .d_max_ovsp_dl = 8,
+ .d_gsm_bgd_mgt = 0,
+ /* we don't set the FIR coefficients !?! */
+};
diff --git a/src/target/firmware/calypso/du.c b/src/target/firmware/calypso/du.c
new file mode 100644
index 00000000..58783b06
--- /dev/null
+++ b/src/target/firmware/calypso/du.c
@@ -0,0 +1,51 @@
+/* Calypso DU (Debug Unit) Driver */
+
+/* (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <memory.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <calypso/du.h>
+
+#define BASE_ADDR_DU 0x03c00000
+#define DU_REG(m) (BASE_ADDR_DU+(m))
+
+void calypso_du_init() {
+ unsigned char c;
+ calypso_debugunit(1);
+ for(c = 0; c < 64; c++) {
+ writew(DU_REG(c), 0x00000000);
+ }
+}
+
+void calypso_du_stop() {
+ calypso_debugunit(0);
+}
+
+void calypso_du_dump() {
+ unsigned char c;
+ puts("Debug unit traceback:\n");
+ for(c = 0; c < 64; c++) {
+ uint32_t w = readw(DU_REG(c));
+ printf("t-%2x: 0x%8x\n", c, (unsigned int)w);
+ }
+}
diff --git a/src/target/firmware/calypso/i2c.c b/src/target/firmware/calypso/i2c.c
new file mode 100644
index 00000000..bf441780
--- /dev/null
+++ b/src/target/firmware/calypso/i2c.c
@@ -0,0 +1,123 @@
+/* Driver for I2C Master Controller inside TI Calypso */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <i2c.h>
+
+#define BASE_ADDR_I2C 0xfffe2800
+#define I2C_REG(x) (BASE_ADDR_I2C+(x))
+
+enum i2c_reg {
+ DEVICE_REG = 0,
+ ADDRESS_REG,
+ DATA_WR_REG,
+ DATA_RD_REG,
+ CMD_REG,
+ CONF_FIFO_REG,
+ CONF_CLK_REG,
+ CONF_CLK_FUNC_REF,
+ STATUS_FIFO_REG,
+ STATUS_ACTIVITY_REG,
+};
+
+#define I2C_CMD_SOFT_RESET (1 << 0)
+#define I2C_CMD_EN_CLK (1 << 1)
+#define I2C_CMD_START (1 << 2)
+#define I2C_CMD_RW_READ (1 << 3)
+#define I2C_CMD_COMP_READ (1 << 4)
+#define I2C_CMD_IRQ_ENABLE (1 << 5)
+
+#define I2C_STATUS_ERROR_DATA (1 << 0)
+#define I2C_STATUS_ERROR_DEV (1 << 1)
+#define I2C_STATUS_IDLE (1 << 2) // 1: not idle, 0: idle
+#define I2C_STATUS_INTERRUPT (1 << 3)
+
+int i2c_write(uint8_t chip, uint32_t addr, int alen, const uint8_t *buffer, int len)
+{
+ uint8_t cmd;
+
+ /* Calypso I2C controller doesn't support fancy addressing */
+ if (alen > 1)
+ return -1;
+
+ /* FIXME: implement writes longer than fifo size */
+ if (len > 16)
+ return -1;
+
+ printd("i2c_write(chip=0x%02u, addr=0x%02u): ", chip, addr);
+
+ writeb(chip & 0x7f, I2C_REG(DEVICE_REG));
+ writeb(addr & 0xff, I2C_REG(ADDRESS_REG));
+
+ /* we have to tell the controller how many bits we'll put into the fifo ?!? */
+ writeb(len-1, I2C_REG(CONF_FIFO_REG));
+
+ /* fill the FIFO */
+ while (len--) {
+ uint8_t byte = *buffer++;
+ writeb(byte, I2C_REG(DATA_WR_REG));
+ printd("%02X ", byte);
+ }
+ dputchar('\n');
+
+ /* start the transfer */
+ cmd = readb(I2C_REG(CMD_REG));
+ cmd |= I2C_CMD_START;
+ writeb(cmd, I2C_REG(CMD_REG));
+
+ /* wait until transfer completes */
+ while (1) {
+ uint8_t reg = readb(I2C_REG(STATUS_ACTIVITY_REG));
+ printd("I2C Status: 0x%02x\n", reg & 0xf);
+ if (!(reg & I2C_STATUS_IDLE)) // 0: idle 1: not idle
+ break;
+ }
+ dputs("I2C transfer completed\n");
+
+ return 0;
+}
+
+void i2c_init(int speed, int slaveadd)
+{
+ /* scl_out = clk_func_ref / 3,
+ clk_func_ref = master_clock_freq / (divisor_2 + 1)
+ master_clock_freq = ext_clock_freq / divisor_1 */
+ /* clk_func_ref = scl_out * 3,
+ divisor_2 = (master_clock_freq / clk_func_ref) - 1
+ divisor_1 = ext_clock_freq / master_clock_freq */
+ /* for a target freq of 200kHz:
+ ext_clock_freq = 13MHz
+ clk_func_ref = 3 * 300kHZ = 600kHz
+ divisor_1 = 1 => master_clock_freq = ext_clock_freq = 13MHz
+ divisor_2 = 21 => clk_func_ref = 13MHz / (21+2) = 590.91 kHz
+ scl_out = clk_func_ref / 3 = 509.91 kHz / 3 = 196.97kHz */
+ writeb(I2C_CMD_SOFT_RESET, I2C_REG(CMD_REG));
+
+ writeb(0x00, I2C_REG(CONF_CLK_REG));
+ writeb(21, I2C_REG(CONF_CLK_FUNC_REF));
+
+ writeb(I2C_CMD_EN_CLK, I2C_REG(CMD_REG));
+}
diff --git a/src/target/firmware/calypso/irq.c b/src/target/firmware/calypso/irq.c
new file mode 100644
index 00000000..136fd55e
--- /dev/null
+++ b/src/target/firmware/calypso/irq.c
@@ -0,0 +1,266 @@
+/* Driver for Calypso IRQ controller */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <arm.h>
+#include <calypso/irq.h>
+
+#define BASE_ADDR_IRQ 0xfffffa00
+
+enum irq_reg {
+ IT_REG1 = 0x00,
+ IT_REG2 = 0x02,
+ MASK_IT_REG1 = 0x08,
+ MASK_IT_REG2 = 0x0a,
+ IRQ_NUM = 0x10,
+ FIQ_NUM = 0x12,
+ IRQ_CTRL = 0x14,
+};
+
+#define ILR_IRQ(x) (0x20 + (x*2))
+#define IRQ_REG(x) ((void *)BASE_ADDR_IRQ + (x))
+
+#define NR_IRQS 32
+
+static uint8_t default_irq_prio[] = {
+ [IRQ_WATCHDOG] = 0xff,
+ [IRQ_TIMER1] = 0xff,
+ [IRQ_TIMER2] = 0xff,
+ [IRQ_TSP_RX] = 0,
+ [IRQ_TPU_FRAME] = 3,
+ [IRQ_TPU_PAGE] = 0xff,
+ [IRQ_SIMCARD] = 0xff,
+ [IRQ_UART_MODEM] = 8,
+ [IRQ_KEYPAD_GPIO] = 4,
+ [IRQ_RTC_TIMER] = 9,
+ [IRQ_RTC_ALARM_I2C] = 10,
+ [IRQ_ULPD_GAUGING] = 2,
+ [IRQ_EXTERNAL] = 12,
+ [IRQ_SPI] = 0xff,
+ [IRQ_DMA] = 0xff,
+ [IRQ_API] = 0xff,
+ [IRQ_SIM_DETECT] = 0,
+ [IRQ_EXTERNAL_FIQ] = 7,
+ [IRQ_UART_IRDA] = 2,
+ [IRQ_ULPD_GSM_TIMER] = 1,
+ [IRQ_GEA] = 0xff,
+};
+
+static irq_handler *irq_handlers[NR_IRQS];
+
+static void _irq_enable(enum irq_nr nr, int enable)
+{
+ uint16_t *reg = IRQ_REG(MASK_IT_REG1);
+ uint16_t val;
+
+ if (nr > 15) {
+ reg = IRQ_REG(MASK_IT_REG2);
+ nr -= 16;
+ }
+
+ val = readw(reg);
+ if (enable)
+ val &= ~(1 << nr);
+ else
+ val |= (1 << nr);
+ writew(val, reg);
+}
+
+void irq_enable(enum irq_nr nr)
+{
+ _irq_enable(nr, 1);
+}
+
+void irq_disable(enum irq_nr nr)
+{
+ _irq_enable(nr, 0);
+}
+
+void irq_config(enum irq_nr nr, int fiq, int edge, int8_t prio)
+{
+ uint16_t val;
+
+ if (prio == -1)
+ prio = default_irq_prio[nr];
+
+ if (prio > 31)
+ prio = 31;
+
+ val = prio << 2;
+ if (edge)
+ val |= 0x02;
+ if (fiq)
+ val |= 0x01;
+
+ writew(val, IRQ_REG(ILR_IRQ(nr)));
+}
+
+/* Entry point for interrupts */
+void irq(void)
+{
+ uint8_t num, tmp;
+ irq_handler *handler;
+
+#if 1
+ /* Hardware interrupt detection mode */
+ num = readb(IRQ_REG(IRQ_NUM)) & 0x1f;
+
+ printd("i%02x\n", num);
+
+ handler = irq_handlers[num];
+
+ if (handler)
+ handler(num);
+#else
+ /* Software interrupt detection mode */
+ {
+ uint16_t it_reg, mask_reg;
+ uint32_t irqs;
+
+ it_reg = readw(IRQ_REG(IT_REG1));
+ mask_reg = readw(IRQ_REG(MASK_IT_REG1));
+ irqs = it_reg & ~mask_reg;
+
+ it_reg = readw(IRQ_REG(IT_REG2));
+ mask_reg = readw(IRQ_REG(MASK_IT_REG2));
+ irqs |= (it_reg & ~mask_reg) << 16;
+
+ for (num = 0; num < 32; num++) {
+ if (irqs & (1 << num)) {
+ printd("i%d\n", num);
+ handler = irq_handlers[num];
+ if (handler)
+ handler(num);
+ /* clear this interrupt */
+ if (num < 16)
+ writew(~(1 << num), IRQ_REG(IT_REG1));
+ else
+ writew(~(1 << (num-16)), IRQ_REG(IT_REG2));
+ }
+ }
+ dputchar('\n');
+ }
+#endif
+ /* Start new IRQ agreement */
+ tmp = readb(IRQ_REG(IRQ_CTRL));
+ tmp |= 0x01;
+ writeb(tmp, IRQ_REG(IRQ_CTRL));
+}
+
+/* Entry point for FIQs */
+void fiq(void)
+{
+ uint8_t num, tmp;
+ irq_handler *handler;
+
+ num = readb(IRQ_REG(FIQ_NUM)) & 0x1f;
+ if (num) {
+ printd("f%02x\n", num);
+ }
+
+ handler = irq_handlers[num];
+
+ if (handler)
+ handler(num);
+
+ /* Start new FIQ agreement */
+ tmp = readb(IRQ_REG(IRQ_CTRL));
+ tmp |= 0x02;
+ writeb(tmp, IRQ_REG(IRQ_CTRL));
+}
+
+void irq_register_handler(enum irq_nr nr, irq_handler *handler)
+{
+ if (nr >= NR_IRQS)
+ return;
+
+ irq_handlers[nr] = handler;
+}
+
+#define BASE_ADDR_IBOOT_EXC 0x0080001C
+extern uint32_t _exceptions;
+
+/* Install the exception handlers to where the ROM loader jumps */
+void calypso_exceptions_install(void)
+{
+ uint32_t *exceptions_dst = (uint32_t *) BASE_ADDR_IBOOT_EXC;
+ uint32_t *exceptions_src = &_exceptions;
+ int i;
+
+ for (i = 0; i < 7; i++)
+ *exceptions_dst++ = *exceptions_src++;
+
+}
+
+static void set_default_priorities(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(default_irq_prio); i++) {
+ uint16_t val;
+ uint8_t prio = default_irq_prio[i];
+ if (prio > 31)
+ prio = 31;
+
+ val = readw(IRQ_REG(ILR_IRQ(i)));
+ val &= ~(0x1f << 2);
+ val |= prio << 2;
+ writew(val, IRQ_REG(ILR_IRQ(i)));
+ }
+}
+
+static uint32_t irq_nest_mask;
+/* mask off all interrupts that have a lower priority than irq_nr */
+static void mask_all_lower_prio_irqs(enum irq_nr irqnr)
+{
+ uint8_t our_prio = readb(IRQ_REG(ILR_IRQ(irqnr))) >> 2;
+ int i;
+
+ for (i = 0; i < _NR_IRQ; i++) {
+ uint8_t prio;
+
+ if (i == irqnr)
+ continue;
+
+ prio = readb(IRQ_REG(ILR_IRQ(i))) >> 2;
+ if (prio >= our_prio)
+ irq_nest_mask |= (1 << i);
+ }
+}
+
+void irq_init(void)
+{
+ /* set default priorities */
+ set_default_priorities();
+ /* mask all interrupts off */
+ writew(0xffff, IRQ_REG(MASK_IT_REG1));
+ writew(0xffff, IRQ_REG(MASK_IT_REG2));
+ /* clear all pending interrupts */
+ writew(0, IRQ_REG(IT_REG1));
+ writew(0, IRQ_REG(IT_REG2));
+ /* enable interrupts globally to the ARM core */
+ arm_enable_interrupts();
+}
diff --git a/src/target/firmware/calypso/keypad.c b/src/target/firmware/calypso/keypad.c
new file mode 100644
index 00000000..f2dea9df
--- /dev/null
+++ b/src/target/firmware/calypso/keypad.c
@@ -0,0 +1,207 @@
+/* Driver for the keypad attached to the TI Calypso */
+
+/* (C) 2010 by roh <roh@hyte.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <delay.h>
+#include <memory.h>
+#include <keypad.h>
+
+#include <calypso/irq.h>
+#include <abb/twl3025.h>
+#include <comm/timer.h>
+
+
+#define KBR_LATCH_REG 0xfffe480a
+#define KBC_REG 0xfffe480c
+#define KBD_GPIO_INT 0xfffe4816
+#define KBD_GPIO_MASKIT 0xfffe4818
+
+static key_handler_t key_handler = NULL;
+
+void emit_key(uint8_t key, uint8_t state)
+{
+ printf("key=%u %s\n", key, state == PRESSED ? "pressed" : "released");
+
+ if(key_handler) {
+ key_handler(key, state);
+ }
+}
+
+volatile uint32_t lastbuttons = 0;
+unsigned long power_hold = 0;
+
+#define BTN_TO_KEY(name) \
+ ((diff & BTN_##name) == BTN_##name) \
+ { \
+ key = KEY_##name; \
+ diff = diff & ~BTN_##name; \
+ state = (buttons & BTN_##name) ? PRESSED : RELEASED; \
+ }
+
+void dispatch_buttons(uint32_t buttons)
+{
+ uint8_t state;
+
+ if ((buttons & BTN_POWER)) {
+ /* hold button 500ms to shut down */
+ if ((lastbuttons & BTN_POWER)) {
+ unsigned long elapsed = jiffies - power_hold;
+ if (elapsed > 50)
+ twl3025_power_off();
+ power_hold++;
+ } else
+ power_hold = jiffies;
+ }
+
+ if (buttons == lastbuttons)
+ return;
+
+ uint32_t diff = buttons ^ lastbuttons;
+ uint8_t key=KEY_INV;
+
+ while (diff != 0)
+ {
+ if BTN_TO_KEY(POWER)
+ else if BTN_TO_KEY(0)
+ else if BTN_TO_KEY(1)
+ else if BTN_TO_KEY(2)
+ else if BTN_TO_KEY(3)
+ else if BTN_TO_KEY(4)
+ else if BTN_TO_KEY(5)
+ else if BTN_TO_KEY(6)
+ else if BTN_TO_KEY(7)
+ else if BTN_TO_KEY(8)
+ else if BTN_TO_KEY(9)
+ else if BTN_TO_KEY(STAR)
+ else if BTN_TO_KEY(HASH)
+ else if BTN_TO_KEY(MENU)
+ else if BTN_TO_KEY(LEFT_SB)
+ else if BTN_TO_KEY(RIGHT_SB)
+ else if BTN_TO_KEY(UP)
+ else if BTN_TO_KEY(DOWN)
+ else if BTN_TO_KEY(LEFT)
+ else if BTN_TO_KEY(RIGHT)
+ else if BTN_TO_KEY(OK)
+ else
+ {
+ printf("\nunknown keycode: 0x%08x\n", diff);
+ break;
+ }
+ emit_key(key, state);
+ }
+ lastbuttons = buttons;
+}
+
+static uint8_t polling = 0;
+static uint8_t with_interrupts = 0;
+
+static void keypad_irq(__unused enum irq_nr nr)
+{
+ /* enable polling */
+ polling = 1;
+ irq_disable(IRQ_KEYPAD_GPIO);
+}
+
+void keypad_init(uint8_t interrupts)
+{
+ lastbuttons = 0;
+ polling = 0;
+ writew(0, KBD_GPIO_MASKIT);
+ writew(0, KBC_REG);
+
+ if(interrupts) {
+ with_interrupts = 1;
+ irq_register_handler(IRQ_KEYPAD_GPIO, &keypad_irq);
+ irq_config(IRQ_KEYPAD_GPIO, 0, 0, 0);
+ irq_enable(IRQ_KEYPAD_GPIO);
+ }
+}
+
+void keypad_set_handler(key_handler_t handler)
+{
+ key_handler = handler;
+}
+
+void keypad_poll()
+{
+ static uint16_t reg;
+ static uint16_t col;
+ static uint32_t buttons = 0, debounce1 = 0, debounce2 = 0;
+
+ if (with_interrupts && !polling)
+ return;
+
+ /* start polling */
+ if (polling == 1) {
+ writew(0x1f & ~0x1, KBC_REG); /* first col */
+ col = 0;
+ polling = 2;
+ return;
+ }
+
+ /* enable keypad irq after the signal settles */
+ if (polling == 3) {
+ if(with_interrupts) {
+ irq_enable(IRQ_KEYPAD_GPIO);
+ polling = 0;
+ } else {
+ polling = 1;
+ }
+ return;
+ }
+
+ reg = readw(KBR_LATCH_REG);
+ buttons = (buttons & ~(0x1f << (col * 5)))
+ | ((~reg & 0x1f) << (col * 5 ));
+ /* if key is released, stay in column for faster debounce */
+ if ((debounce1 | debounce2) & ~buttons) {
+ debounce2 = debounce1;
+ debounce1 = buttons;
+ return;
+ }
+
+ col++;
+ if (col > 4) {
+ col = 0;
+ /* if power button, ignore other states */
+ if (buttons & BTN_POWER)
+ buttons = lastbuttons | BTN_POWER;
+ else if (lastbuttons & BTN_POWER)
+ buttons = lastbuttons & ~BTN_POWER;
+ dispatch_buttons(buttons);
+ if (buttons == 0) {
+ writew(0x0, KBC_REG);
+ polling = 3;
+ return;
+ }
+ }
+ if (col == 4)
+ writew(0xff, KBC_REG);
+ else
+ writew(0x1f & ~(0x1 << col ), KBC_REG);
+
+}
+
diff --git a/src/target/firmware/calypso/misc.c b/src/target/firmware/calypso/misc.c
new file mode 100644
index 00000000..460cc5d5
--- /dev/null
+++ b/src/target/firmware/calypso/misc.c
@@ -0,0 +1,60 @@
+
+#include <stdint.h>
+#include <stdio.h>
+#include <memory.h>
+
+/* dump a memory range */
+void memdump_range(unsigned int *ptr, unsigned int len)
+{
+ unsigned int *end = ptr + (len/4);
+ unsigned int *tmp;
+
+ for (tmp = ptr; tmp < end; tmp += 8) {
+ int i;
+ printf("%08X: ", (unsigned int) tmp);
+
+ for (i = 0; i < 8; i++)
+ printf("%08X %s", *(tmp+i), i == 3 ? " " : "");
+
+ putchar('\n');
+ }
+}
+
+#define KBIT 1024
+#define MBIT (1024*KBIT)
+void dump_mem(void)
+{
+ puts("Dump 64kBits of internal ROM\n");
+ memdump_range((void *)0x03800000, 64*KBIT/8);
+
+ puts("Dump 8Mbits of external flash\n");
+ memdump_range((void *)0x00000000, 8*MBIT/8);
+
+ puts("Dump 2Mbits of internal RAM\n");
+ memdump_range((void *)0x00800000, 2*MBIT/8);
+
+ puts("Dump 2Mbits of external RAM\n");
+ memdump_range((void *)0x01000000, 2*MBIT/8);
+}
+
+#define REG_DEV_ID_CODE 0xfffef000
+#define REG_DEV_VER_CODE 0xfffef002
+#define REG_DEV_ARMVER_CODE 0xfffffe00
+#define REG_cDSP_ID_CODE 0xfffffe02
+#define REG_DIE_ID_CODE 0xfffef010
+
+void dump_dev_id(void)
+{
+ int i;
+
+ printf("Device ID code: 0x%04x\n", readw(REG_DEV_ID_CODE));
+ printf("Device Version code: 0x%04x\n", readw(REG_DEV_VER_CODE));
+ printf("ARM ID code: 0x%04x\n", readw(REG_DEV_ARMVER_CODE));
+ printf("cDSP ID code: 0x%04x\n", readw(REG_cDSP_ID_CODE));
+ puts("Die ID code: ");
+ for (i = 0; i < 64/8; i += 4)
+ printf("%08x", readl(REG_DIE_ID_CODE+i));
+ putchar('\n');
+}
+
+
diff --git a/src/target/firmware/calypso/rtc.c b/src/target/firmware/calypso/rtc.c
new file mode 100644
index 00000000..45d759f3
--- /dev/null
+++ b/src/target/firmware/calypso/rtc.c
@@ -0,0 +1,78 @@
+/* Driver for Calypso RTC controller */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <calypso/irq.h>
+
+#define BASE_ADDR_RTC 0xfffe1800
+#define RTC_REG(x) ((void *)BASE_ADDR_RTC + (x))
+
+enum rtc_reg {
+ SECOND_REG = 0x00,
+ MINUTES_REG = 0x01,
+ HOURS_REG = 0x02,
+ DAYS_REG = 0x03,
+ MONTHS_REG = 0x04,
+ YEARS_REG = 0x05,
+ WEEK_REG = 0x06,
+ /* reserved */
+ ALARM_SECOND_REG = 0x08,
+ ALARM_MINUTES_REG = 0x09,
+ ALARM_HOURS_REG = 0x0a,
+ ALARM_DAYS_REG = 0x0b,
+ ALARM_MONTHS_REG = 0x0c,
+ ALARM_YEARS_REG = 0x0d,
+ /* reserved */
+ /* reserved */
+ CTRL_REG = 0x10,
+ STATUS_REG = 0x11,
+ INT_REG = 0x12,
+ COMP_LSB_REG = 0x13,
+ COMP_MSB_REG = 0x14,
+ RES_PROG_REG = 0x15,
+};
+
+static int tick_ctr;
+
+static void rtc_irq_tick(__unused enum irq_nr nr)
+{
+ tick_ctr++;
+}
+
+void rtc_init(void)
+{
+ irq_register_handler(IRQ_RTC_TIMER, &rtc_irq_tick);
+ irq_config(IRQ_RTC_TIMER, 0, 1, 0);
+ irq_enable(IRQ_RTC_TIMER);
+
+ /* clear power-up reset */
+ writeb(0x80, RTC_REG(STATUS_REG));
+ /* enable RTC running */
+ writeb(0x01, RTC_REG(CTRL_REG));
+ /* enable periodic interrupts every second */
+ writeb(0x04, RTC_REG(INT_REG));
+}
diff --git a/src/target/firmware/calypso/sim.c b/src/target/firmware/calypso/sim.c
new file mode 100644
index 00000000..752628fd
--- /dev/null
+++ b/src/target/firmware/calypso/sim.c
@@ -0,0 +1,741 @@
+/* Driver for Simcard Controller inside TI Calypso/Iota */
+
+/* (C) 2010 by Philipp Fabian Benedikt Maier <philipp-maier@runningserver.com>
+ * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/* Uncomment to debug sim */
+/* #define DEBUG */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <string.h>
+#include <delay.h>
+#include <osmocom/core/msgb.h>
+#include <layer1/l23_api.h>
+#include <abb/twl3025.h>
+#include <calypso/sim.h>
+#include <calypso/irq.h>
+
+#include <l1ctl_proto.h>
+
+#define SIM_CLASS 0xA0
+ /* Class that contains the following instructions */
+#define SIM_GET_RESPONSE 0xC0
+ /* Get the response of a command from the card */
+#define SIM_READ_BINARY 0xB0 /* Read file in binary mode */
+#define SIM_READ_RECORD 0xB2 /* Read record in binary mode */
+
+enum {
+ SIM_STATE_IDLE,
+ SIM_STATE_TX_HEADER,
+ SIM_STATE_RX_STATUS,
+ SIM_STATE_RX_ACK,
+ SIM_STATE_RX_ACK_DATA,
+ SIM_STATE_TX_DATA,
+};
+
+#define L3_MSG_HEAD 4
+
+static uint8_t sim_data[256]; /* buffer for SIM command */
+static volatile uint16_t sim_len = 0; /* lenght of data in sim_data[] */
+static volatile uint8_t sim_state = SIM_STATE_IDLE;
+ /* current state of SIM process */
+static volatile uint8_t sim_ignore_waiting_char = 0;
+ /* signal ignoring of NULL procedure byte */
+static volatile int sim_rx_character_count = 0;
+ /* How many bytes have been received by calypso_sim_receive() */
+static volatile int sim_rx_max_character_count = 0;
+ /* How many bytes have been received by calypso_sim_receive() */
+static volatile int sim_tx_character_count = 0;
+ /* How many bytes have been transmitted by calypso_sim_transmit() */
+static volatile int sim_tx_character_length = 0;
+ /* How many bytes have to be transmitted by calypso_sim_transmit() */
+static uint8_t *rx_buffer = 0;
+ /* RX-Buffer that is issued by calypso_sim_receive() */
+static uint8_t *tx_buffer = 0;
+ /* TX-Buffer that is issued by calypso_sim_transmit() */
+static volatile int rxDoneFlag = 0;
+ /* Used for rx synchronization instead of a semaphore in calypso_sim_receive() */
+static volatile int txDoneFlag = 0;
+ /* Used for rx synchronization instead of a semaphore in calypso_sim_transmit() */
+
+/* Display Register dump */
+void calypso_sim_regdump(void)
+{
+#ifdef DEBUG
+ unsigned int regVal;
+
+#define SIM_DEBUG_OUTPUTDELAY 200
+
+ puts("\n\n\n");
+ puts("====================== CALYPSO SIM REGISTER DUMP =====================\n");
+ puts("Reg_sim_cmd register (R/W) - FFFE:0000\n");
+
+ regVal = readw(REG_SIM_CMD);
+ printf(" |-REG_SIM_CMD = %04x\n", readw(REG_SIM_CMD));
+
+ if(regVal & REG_SIM_CMD_CMDCARDRST)
+ puts(" | |-REG_SIM_CMD_CMDCARDRST = 1 ==> SIM card reset sequence enabled.\n");
+ else
+ puts(" | |-REG_SIM_CMD_CMDCARDRST = 0 ==> SIM card reset sequence disabled.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CMD_CMDIFRST)
+ puts(" | |-REG_SIM_CMD_CMDIFRST = 1\n");
+ else
+ puts(" | |-REG_SIM_CMD_CMDIFRST = 0\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CMD_CMDSTOP)
+ puts(" | |-REG_SIM_CMD_CMDSTOP = 1\n");
+ else
+ puts(" | |-REG_SIM_CMD_CMDSTOP = 0\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CMD_CMDSTART)
+ puts(" | |-REG_SIM_CMD_CMDSTART = 1 ==> SIM card start procedure active.\n");
+ else
+ puts(" | |-REG_SIM_CMD_CMDSTART = 0\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CMD_CMDSTART)
+ puts(" | |-REG_SIM_CMD_MODULE_CLK_EN = 1 ==> Clock of the module enabled.\n");
+ else
+ puts(" | |-REG_SIM_CMD_MODULE_CLK_EN = 0 ==> Clock of the module disabled.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ regVal = readw(REG_SIM_STAT);
+ printf(" |-REG_SIM_STAT = %04x\n", regVal);
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_STAT_STATNOCARD)
+ puts(" | |-REG_SIM_STAT_STATNOCARD = 1 ==> No card!\n");
+ else
+ puts(" | |-REG_SIM_STAT_STATNOCARD = 0 ==> Card detected!\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_STAT_STATTXPAR)
+ puts(" | |-REG_SIM_STAT_STATTXPAR = 1 ==> Parity ok!\n");
+ else
+ puts(" | |-REG_SIM_STAT_STATTXPAR = 0 ==> Parity error!\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_STAT_STATFIFOFULL)
+ puts(" | |-REG_SIM_STAT_STATFIFOFULL = 1 ==> Fifo full!\n");
+ else
+ puts(" | |-REG_SIM_STAT_STATFIFOFULL = 0\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_STAT_STATFIFOEMPTY)
+ puts(" | |-REG_SIM_STAT_STATFIFOEMPTY = 1 ==> Fifo empty!\n");
+ else
+ puts(" | |-REG_SIM_STAT_STATFIFOEMPTY = 0\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ regVal = readw(REG_SIM_CONF1);
+ printf(" |-REG_SIM_CONF1 = %04x\n", regVal);
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFCHKPAR)
+ puts(" | |-REG_SIM_CONF1_CONFCHKPAR = 1 ==> Parity check on reception enabled.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFCHKPAR = 0 ==> Parity check on reception disabled.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFCODCONV)
+ puts(" | |-REG_SIM_CONF1_CONFCODCONV = 1 ==> Coding convention is inverse.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFCODCONV = 0 ==> Coding convention is direct (normal).\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFTXRX)
+ puts(" | |-REG_SIM_CONF1_CONFTXRX = 1 ==> SIO line direction is in transmit mode.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFTXRX = 0 ==> SIO line direction is in receive mode.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFSCLKEN)
+ puts(" | |-REG_SIM_CONF1_CONFSCLKEN = 1 ==> SIM clock in normal mode.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFSCLKEN = 0 ==> SIM clock in standby mode.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_reserved)
+ puts(" | |-REG_SIM_CONF1_reserved = 1 ==> ETU period is 4*1/Fsclk.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_reserved = 0 ==> ETU period is CONFETUPERIOD.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFSCLKDIV)
+ puts(" | |-REG_SIM_CONF1_CONFSCLKDIV = 1 ==> SIM clock frequency is 13/8 Mhz.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFSCLKDIV = 0 ==> SIM clock frequency is 13/4 Mhz.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFSCLKLEV)
+ puts(" | |-REG_SIM_CONF1_CONFSCLKLEV = 1 ==> SIM clock idle level is high.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFSCLKLEV = 0 ==> SIM clock idle level is low.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFETUPERIOD)
+ puts(" | |-REG_SIM_CONF1_CONFETUPERIOD = 1 ==> ETU period is 512/8*1/Fsclk.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFETUPERIOD = 0 ==> ETU period is 372/8*1/Fsclk.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFBYPASS)
+ puts(" | |-REG_SIM_CONF1_CONFBYPASS = 1 ==> Hardware timers and start and stop sequences are bypassed.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFBYPASS = 0 ==> Hardware timers and start and stop sequences are normal.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFSVCCLEV)
+ puts(" | |-REG_SIM_CONF1_CONFSVCCLEV = 1 ==> SVCC Level is high (Only valid when CONFBYPASS = 1).\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFSVCCLEV = 0 ==> SVCC Level is low (Only valid when CONFBYPASS = 1).\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFSRSTLEV)
+ puts(" | |-REG_SIM_CONF1_CONFSRSTLEV = 1 ==> SRST Level is high (Only valid when CONFBYPASS = 1).\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFSRSTLEV = 0 ==> SRST Level is low (Only valid when CONFBYPASS = 1).\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ printf(" | |-REG_SIM_CONF1_CONFTRIG = 0x%x (FIFO trigger level)\n",(regVal >> REG_SIM_CONF1_CONFTRIG) & REG_SIM_CONF1_CONFTRIG_MASK);
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_CONF1_CONFSIOLOW)
+ puts(" | |-REG_SIM_CONF1_CONFSIOLOW = 1 ==> I/O is forced to low.\n");
+ else
+ puts(" | |-REG_SIM_CONF1_CONFSIOLOW = 0\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ regVal = readw(REG_SIM_CONF2);
+ printf(" |-REG_SIM_CONF2 = %04x\n", regVal);
+ printf(" | |-REG_SIM_CONF2_CONFTFSIM = 0x%x (time delay for filtering of SIM_CD)\n",(regVal >> REG_SIM_CONF2_CONFTFSIM) & REG_SIM_CONF2_CONFTFSIM_MASK);
+ printf(" | |-REG_SIM_CONF2_CONFTDSIM = 0x%x (time delay for contact activation/deactivation)\n",(regVal >> REG_SIM_CONF2_CONFTDSIM) & REG_SIM_CONF2_CONFTDSIM_MASK);
+ printf(" | |-REG_SIM_CONF2_CONFWAITI = 0x%x (CONFWAITI overflow wait time between two received chars)\n",(regVal >> REG_SIM_CONF2_CONFWAITI) & REG_SIM_CONF2_CONFWAITI_MASK);
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ regVal = readw(REG_SIM_IT);
+ printf(" |-REG_SIM_IT = %04x\n", regVal);
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_IT_SIM_NATR)
+ puts(" | |-REG_SIM_IT_SIM_NATR = 1 ==> No answer to reset!\n");
+ else
+ puts(" | |-REG_SIM_IT_SIM_NATR = 0 ==> On read access to REG_SIM_IT.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_IT_SIM_WT)
+ puts(" | |-REG_SIM_IT_SIM_WT = 1 ==> Character underflow!\n");
+ else
+ puts(" | |-REG_SIM_IT_SIM_WT = 0 ==> On read access to REG_SIM_IT.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_IT_SIM_OV)
+ puts(" | |-REG_SIM_IT_SIM_OV = 1 ==> Receive overflow!\n");
+ else
+ puts(" | |-REG_SIM_IT_SIM_OV = 0 ==> On read access to REG_SIM_IT.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_IT_SIM_TX)
+ puts(" | |-REG_SIM_IT_SIM_TX = 1 ==> Waiting for character to transmit...\n");
+ else
+ {
+ puts(" | |-REG_SIM_IT_SIM_TX = 0 ==> On write access to REG_SIM_DTX or on switching\n");
+ puts(" | | from transmit to receive mode (CONFTXRX bit)\n");
+ }
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_IT_SIM_RX)
+ puts(" | |-REG_SIM_IT_SIM_RX = 1 ==> Waiting characters to be read...\n");
+ else
+ puts(" | |-REG_SIM_IT_SIM_RX = 0 ==> On read access to REG_SIM_DRX.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ regVal = readw(REG_SIM_DRX);
+ printf(" |-REG_SIM_DRX = %04x\n", regVal);
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ printf(" | |-REG_SIM_DRX_SIM_DRX = 0x%x (next data byte in FIFO available for reading)\n",(regVal >> REG_SIM_DRX_SIM_DRX) & REG_SIM_DRX_SIM_DRX_MASK);
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_DRX_STATRXPAR)
+ puts(" | |-REG_SIM_DRX_STATRXPAR = 1 ==> Parity Ok.\n");
+ else
+ puts(" | |-REG_SIM_DRX_STATRXPAR = 0 ==> Parity error!\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ regVal = readw(REG_SIM_DTX);
+ printf(" |-REG_SIM_DTX = %02x (next data byte to be transmitted)\n", regVal);
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ regVal = readw(REG_SIM_MASKIT);
+ printf(" |-REG_SIM_MASKIT = %04x\n", regVal);
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_MASKIT_MASK_SIM_NATR)
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_NATR = 1 ==> No-answer-to-reset interrupt is masked.\n");
+ else
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_NATR = 0 ==> No-answer-to-reset interrupt is unmasked.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_MASKIT_MASK_SIM_WT)
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_WT = 1 ==> Character wait-time overflow interrupt is masked.\n");
+ else
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_WT = 0 ==> Character wait-time overflow interrupt is unmasked.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_MASKIT_MASK_SIM_OV)
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_OV = 1 ==> Receive overflow interrupt is masked.\n");
+ else
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_OV = 0 ==> Receive overflow interrupt is unmasked.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_MASKIT_MASK_SIM_TX)
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_TX = 1 ==> Waiting characters to be transmit interrupt is masked.\n");
+ else
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_TX = 0 ==> Waiting characters to be transmit interrupt is unmasked.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_MASKIT_MASK_SIM_RX)
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_RX = 1 ==> Waiting characters to be read interrupt is masked.\n");
+ else
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_RX = 0 ==> Waiting characters to be read interrupt is unmasked.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ if(regVal & REG_SIM_MASKIT_MASK_SIM_CD)
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_CD = 1 ==> SIM card insertion/extraction interrupt is masked.\n");
+ else
+ puts(" | |-REG_SIM_MASKIT_MASK_SIM_CD = 0 ==> SIM card insertion/extraction interrupt is unmasked.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+
+ regVal = REG_SIM_IT_CD;
+ printf(" |-REG_SIM_IT_CD = %04x\n", regVal);
+ if(regVal & REG_SIM_IT_CD_IT_CD)
+ puts(" |-REG_SIM_IT_CD_IT_CD = 1 ==> SIM card insertion/extraction interrupt is masked.\n");
+ else
+ puts(" |-REG_SIM_IT_CD_IT_CD = 0 ==> SIM card insertion/extraction interrupt is unmasked.\n");
+ delay_ms(SIM_DEBUG_OUTPUTDELAY);
+#endif
+ return;
+}
+
+/* Receive raw data through the sim interface */
+int calypso_sim_receive(uint8_t *data, uint8_t len)
+{
+ printd("Triggering SIM reception\n");
+
+ /* Prepare buffers and flags */
+ rx_buffer = data;
+ sim_rx_character_count = 0;
+ rxDoneFlag = 0;
+ sim_rx_max_character_count = len;
+
+ /* Switch I/O direction to input */
+ writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFTXRX, REG_SIM_CONF1);
+
+ /* Unmask the interrupts that are needed to perform this action */
+ writew(~(REG_SIM_MASKIT_MASK_SIM_RX | REG_SIM_MASKIT_MASK_SIM_WT),
+ REG_SIM_MASKIT);
+
+ return 0;
+}
+
+/* Transmit raw data through the sim interface */
+int calypso_sim_transmit(uint8_t *data, int length)
+{
+ printd("Triggering SIM transmission\n");
+
+ /* Prepare buffers and flags */
+ tx_buffer = data;
+ sim_tx_character_count = 0;
+ txDoneFlag = 0;
+ sim_tx_character_length = length;
+
+ /* Switch I/O direction to output */
+ writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFTXRX, REG_SIM_CONF1);
+
+ /* Unmask the interrupts that are needed to perform this action */
+ writew(~(REG_SIM_MASKIT_MASK_SIM_TX), REG_SIM_MASKIT);
+
+ /* Transmit the first byte manually to start the interrupt cascade */
+ writew(*tx_buffer,REG_SIM_DTX);
+ tx_buffer++;
+ sim_tx_character_count++;
+
+ return 0;
+}
+
+
+/* IRQ-Handler for simcard interface */
+void sim_irq_handler(enum irq_nr irq)
+{
+ int regVal = readw(REG_SIM_IT);
+
+
+ /* Display interrupt information */
+ printd("SIM-ISR: ");
+
+ if(regVal & REG_SIM_IT_SIM_NATR) {
+ printd(" No answer to reset!\n");
+ }
+
+ /* Used by: calypso_sim_receive() to determine when the transmission
+ * is over
+ */
+ if(regVal & REG_SIM_IT_SIM_WT) {
+ printd(" Character underflow!\n");
+ rxDoneFlag = 1;
+
+ }
+
+ if(regVal & REG_SIM_IT_SIM_OV) {
+ printd(" Receive overflow!\n");
+ }
+
+ /* Used by: calypso_sim_transmit() to transmit the data */
+ if(regVal & REG_SIM_IT_SIM_TX) {
+ printd(" Waiting for transmit...\n");
+ if(sim_tx_character_count >= sim_tx_character_length) {
+ txDoneFlag = 1;
+ } else {
+ writew(*tx_buffer,REG_SIM_DTX);
+ tx_buffer++;
+ sim_tx_character_count++;
+
+ /* its essential to immediately switch to RX after TX
+ * is done
+ */
+ if(sim_tx_character_count >= sim_tx_character_length) {
+ /* TODO: set a proper delay here, 4 is to
+ long if not debugging and no delay is too
+ short */
+// delay_ms(1);
+ /* Switch I/O direction to input */
+ writew(readw(REG_SIM_CONF1) &
+ ~REG_SIM_CONF1_CONFTXRX, REG_SIM_CONF1);
+ }
+ }
+ }
+
+ /* Used by: calypso_sim_receive() to receive the incoming data */
+ if(regVal & REG_SIM_IT_SIM_RX) {
+ uint8_t ch = (uint8_t) (readw(REG_SIM_DRX) & 0xFF);
+
+ /* ignore NULL procedure byte */
+ if(ch == 0x60 && sim_ignore_waiting_char) {
+ printd(" 0x60 received...\n");
+ return;
+ }
+
+ printd(" Waiting for read (%02X)...\n", ch);
+
+ /* Increment character count - this is what
+ * calypso_sim_receive() hands back
+ */
+ sim_rx_character_count++;
+
+ /* Read byte from rx-fifo and write it to the issued buffer */
+ *rx_buffer = ch;
+ rx_buffer++;
+
+ /* to maximise SIM access speed, stop waiting after
+ all the expected characters have been received. */
+ if (sim_rx_max_character_count
+ && sim_rx_character_count >= sim_rx_max_character_count) {
+ printd(" Max characters received!\n");
+ rxDoneFlag = 1;
+ }
+ }
+}
+
+/* simm command from layer 23 */
+void sim_apdu(uint16_t len, uint8_t *data)
+{
+ if (sim_state != SIM_STATE_IDLE) {
+ puts("Sim reader currently busy...\n");
+ return;
+ }
+ memcpy(sim_data, data, len);
+ sim_len = len;
+}
+
+/* handling sim events */
+void sim_handler(void)
+{
+ static struct msgb *msg;
+ struct l1ctl_hdr *l1h;
+ static uint8_t mode;
+ static uint8_t *response;
+ static uint16_t length;
+
+ switch (sim_state) {
+ case SIM_STATE_IDLE:
+ if (!sim_len)
+ break; /* wait for SIM command */
+ /* check if instructions expects a response */
+ if (/* GET RESPONSE needs SIM_APDU_GET */
+ (sim_len == 5 && sim_data[0] == SIM_CLASS &&
+ sim_data[1] == SIM_GET_RESPONSE && sim_data[2] == 0x00 &&
+ sim_data[3] == 0x00) ||
+ /* READ BINARY/RECORD needs SIM_APDU_GET */
+ (sim_len >= 5 && sim_data[0] == SIM_CLASS &&
+ (sim_data[1] == SIM_READ_BINARY ||
+ sim_data[1] == SIM_READ_RECORD)))
+ mode = SIM_APDU_GET;
+ else
+ mode = SIM_APDU_PUT;
+
+ length = sim_data[4];
+
+ /* allocate space for expected response */
+ msg = msgb_alloc_headroom(256, L3_MSG_HEAD
+ + sizeof(struct l1ctl_hdr), "l1ctl1");
+ response = msgb_put(msg, length + 2 + 1);
+
+ sim_state = SIM_STATE_TX_HEADER;
+
+ /* send APDU header */
+ calypso_sim_transmit(sim_data, 5);
+ break;
+ case SIM_STATE_TX_HEADER:
+ if (!txDoneFlag)
+ break; /* wait until header is transmitted */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* Case 1: No input, No Output */
+ if (length == 0) {
+ sim_state = SIM_STATE_RX_STATUS;
+ calypso_sim_receive(response + 1, 2);
+ break;
+ }
+ /* Case 2: No input / Output of known length */
+ if (mode == SIM_APDU_PUT) {
+ sim_state = SIM_STATE_RX_ACK;
+ calypso_sim_receive(response, 1);
+ break;
+ /* Case 4: Input / No output */
+ } else {
+ sim_state = SIM_STATE_RX_ACK_DATA;
+ calypso_sim_receive(response, length + 1 + 2);
+ }
+ break;
+ case SIM_STATE_RX_STATUS:
+ if (!rxDoneFlag)
+ break; /* wait until data is received */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* disable special ignore case */
+ sim_ignore_waiting_char = 0;
+ /* wrong number of bytes received */
+ if (sim_rx_character_count != 2) {
+ puts("SIM: Failed to read status\n");
+ goto error;
+ }
+ msgb_pull(msg, length + 1); /* pull up to status info */
+ goto queue;
+ case SIM_STATE_RX_ACK:
+ if (!rxDoneFlag)
+ break; /* wait until data is received */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* error received */
+ if (sim_rx_character_count == 2) {
+ puts("SIM: command failed\n");
+ msgb_pull(msg, msg->len - 2);
+ msg->data[0] = response[0];
+ msg->data[1] = response[1];
+ goto queue;
+ }
+ /* wrong number of bytes received */
+ if (sim_rx_character_count != 1) {
+ puts("SIM: ACK read failed\n");
+ goto error;
+ }
+ if (response[0] != sim_data[1]) {
+ puts("SIM: ACK does not match request\n");
+ goto error;
+ }
+ sim_state = SIM_STATE_TX_DATA;
+ calypso_sim_transmit(sim_data + 5, length);
+ break;
+ case SIM_STATE_TX_DATA:
+ if (!txDoneFlag)
+ break; /* wait until data is transmitted */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* Ignore waiting char for RUN GSM ALGORITHM */
+ /* TODO: implement proper handling of the "Procedure Bytes"
+ than this is no longer needed */
+ if(sim_data[1] == 0x88)
+ sim_ignore_waiting_char = 1;
+ sim_state = SIM_STATE_RX_STATUS;
+ calypso_sim_receive(response + length + 1, 2);
+ break;
+ case SIM_STATE_RX_ACK_DATA:
+ if (!rxDoneFlag)
+ break; /* wait until data is received */
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+ /* error received */
+ if (sim_rx_character_count == 2) {
+ puts("SIM: command failed\n");
+ msgb_pull(msg, msg->len - 2);
+ msg->data[0] = response[0];
+ msg->data[1] = response[1];
+ goto queue;
+ }
+ /* wrong number of bytes received */
+ if (sim_rx_character_count != length + 1 + 2) {
+ puts("SIM: Failed to read data\n");
+ goto error;
+ }
+ msgb_pull(msg, 1); /* pull ACK byte */
+ goto queue;
+ }
+
+ return;
+
+error:
+ msgb_pull(msg, msg->len - 2);
+ msg->data[0] = 0;
+ msg->data[1] = 0;
+queue:
+ printf("SIM Response (%d): %s\n", msg->len,
+ osmo_hexdump(msg->data, msg->len));
+ l1h = (struct l1ctl_hdr *) msgb_push(msg, sizeof(*l1h));
+ l1h->msg_type = L1CTL_SIM_CONF;
+ l1h->flags = 0;
+ msg->l1h = (uint8_t *)l1h;
+ l1_queue_for_l2(msg);
+ /* go IDLE */
+ sim_state = SIM_STATE_IDLE;
+ sim_len = 0;
+
+ return;
+}
+
+/* Initialize simcard interface */
+void calypso_sim_init(void)
+{
+ /* Register IRQ handler and turn interrupts on */
+ printd("SIM: Registering interrupt handler for simcard-interface\n");
+
+ irq_register_handler(IRQ_SIMCARD, &sim_irq_handler);
+
+#if 1
+ irq_config(IRQ_SIMCARD, 0, 0, 0xff);
+#else
+ irq_config(IRQ_SIMCARD, 0, 0, 1);
+#endif
+
+ irq_enable(IRQ_SIMCARD);
+}
+
+/* Apply power to the simcard (use nullpointer to ignore atr) */
+int calypso_sim_powerup(uint8_t *atr)
+{
+ /* Enable level shifters and voltage regulator */
+#if 1 // 2.9V
+ twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN
+ | VRPCSIM_SIMSEL);
+#else // 1.8V
+ twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN);
+#endif
+ printd(" * Power enabled!\n");
+ delay_ms(SIM_OPERATION_DELAY);
+
+ /* Enable clock */
+ writew(REG_SIM_CMD_MODULE_CLK_EN | REG_SIM_CMD_CMDSTART, REG_SIM_CMD);
+ printd(" * Clock enabled!\n");
+ delay_ms(SIM_OPERATION_DELAY);
+
+ /* Release reset */
+ writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFBYPASS
+ | REG_SIM_CONF1_CONFSRSTLEV
+ | REG_SIM_CONF1_CONFSVCCLEV, REG_SIM_CONF1);
+ printd(" * Reset released!\n");
+
+ /* Catch ATR */
+ if(atr != 0) {
+ calypso_sim_receive(atr, 0);
+ while (!rxDoneFlag)
+ ;
+ }
+
+ return 0;
+}
+
+
+/* Powerdown simcard */
+void calypso_sim_powerdown(void)
+{
+ writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFBYPASS, REG_SIM_CONF1);
+ printd(" * Reset pulled down!\n");
+ delay_ms(SIM_OPERATION_DELAY);
+
+ writew(REG_SIM_CMD_MODULE_CLK_EN | REG_SIM_CMD_CMDSTOP, REG_SIM_CMD);
+ printd(" * Clock disabled!\n");
+ delay_ms(SIM_OPERATION_DELAY);
+
+ writew(0, REG_SIM_CMD);
+ printd(" * Module disabled!\n");
+ delay_ms(SIM_OPERATION_DELAY);
+
+ /* Disable level shifters and voltage regulator */
+ twl3025_reg_write(VRPCSIM, 0);
+ printd(" * Power disabled!\n");
+ delay_ms(SIM_OPERATION_DELAY);
+
+ return;
+}
+
+/* reset the simcard (see note 1) */
+int calypso_sim_reset(uint8_t *atr)
+{
+
+ /* Pull reset down */
+ writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFSRSTLEV,
+ REG_SIM_CONF1);
+ printd(" * Reset pulled down!\n");
+
+ delay_ms(SIM_OPERATION_DELAY);
+
+ /* Pull reset down */
+ writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFSRSTLEV, REG_SIM_CONF1);
+ printd(" * Reset released!\n");
+
+ /* Catch ATR */
+ if(atr != 0) {
+ calypso_sim_receive(atr, 0);
+ while (!rxDoneFlag)
+ ;
+ }
+
+ return 0;
+}
+
diff --git a/src/target/firmware/calypso/spi.c b/src/target/firmware/calypso/spi.c
new file mode 100644
index 00000000..049ac080
--- /dev/null
+++ b/src/target/firmware/calypso/spi.c
@@ -0,0 +1,141 @@
+/* Driver for SPI Master Controller inside TI Calypso */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+//#define DEBUG
+#include <debug.h>
+
+#include <memory.h>
+#include <spi.h>
+#include <delay.h>
+
+#define BASE_ADDR_SPI 0xfffe3000
+#define SPI_REG(n) (BASE_ADDR_SPI+(n))
+
+enum spi_regs {
+ REG_SET1 = 0x00,
+ REG_SET2 = 0x02,
+ REG_CTRL = 0x04,
+ REG_STATUS = 0x06,
+ REG_TX_LSB = 0x08,
+ REG_TX_MSB = 0x0a,
+ REG_RX_LSB = 0x0c,
+ REG_RX_MSB = 0x0e,
+};
+
+#define SPI_SET1_EN_CLK (1 << 0)
+#define SPI_SET1_WR_IRQ_DIS (1 << 4)
+#define SPI_SET1_RDWR_IRQ_DIS (1 << 5)
+
+#define SPI_CTRL_RDWR (1 << 0)
+#define SPI_CTRL_WR (1 << 1)
+#define SPI_CTRL_NB_SHIFT 2
+#define SPI_CTRL_AD_SHIFT 7
+
+#define SPI_STATUS_RE (1 << 0) /* Read End */
+#define SPI_STATUS_WE (1 << 1) /* Write End */
+
+void spi_init(void)
+{
+ writew(SPI_SET1_EN_CLK | SPI_SET1_WR_IRQ_DIS | SPI_SET1_RDWR_IRQ_DIS,
+ SPI_REG(REG_SET1));
+
+ writew(0x0001, SPI_REG(REG_SET2));
+}
+
+int spi_xfer(uint8_t dev_idx, uint8_t bitlen, const void *dout, void *din)
+{
+ uint8_t bytes_per_xfer;
+ uint8_t reg_status, reg_ctrl = 0;
+ uint32_t tmp;
+
+ if (bitlen == 0)
+ return 0;
+
+ if (bitlen > 32)
+ return -1;
+
+ if (dev_idx > 4)
+ return -1;
+
+ bytes_per_xfer = bitlen / 8;
+ if (bitlen % 8)
+ bytes_per_xfer ++;
+
+ reg_ctrl |= (bitlen - 1) << SPI_CTRL_NB_SHIFT;
+ reg_ctrl |= (dev_idx & 0x7) << SPI_CTRL_AD_SHIFT;
+
+ if (bitlen <= 8) {
+ tmp = *(uint8_t *)dout;
+ tmp <<= 24 + (8-bitlen); /* align to MSB */
+ } else if (bitlen <= 16) {
+ tmp = *(uint16_t *)dout;
+ tmp <<= 16 + (16-bitlen); /* align to MSB */
+ } else {
+ tmp = *(uint32_t *)dout;
+ tmp <<= (32-bitlen); /* align to MSB */
+ }
+ printd("spi_xfer(dev_idx=%u, bitlen=%u, data_out=0x%08x): ",
+ dev_idx, bitlen, tmp);
+
+ /* fill transmit registers */
+ writew(tmp >> 16, SPI_REG(REG_TX_MSB));
+ writew(tmp & 0xffff, SPI_REG(REG_TX_LSB));
+
+ /* initiate transfer */
+ if (din)
+ reg_ctrl |= SPI_CTRL_RDWR;
+ else
+ reg_ctrl |= SPI_CTRL_WR;
+ writew(reg_ctrl, SPI_REG(REG_CTRL));
+ printd("reg_ctrl=0x%04x ", reg_ctrl);
+
+ /* wait until the transfer is complete */
+ while (1) {
+ reg_status = readw(SPI_REG(REG_STATUS));
+ printd("status=0x%04x ", reg_status);
+ if (din && (reg_status & SPI_STATUS_RE))
+ break;
+ else if (reg_status & SPI_STATUS_WE)
+ break;
+ }
+ /* FIXME: calibrate how much delay we really need (seven 13MHz cycles) */
+ delay_ms(1);
+
+ if (din) {
+ tmp = readw(SPI_REG(REG_RX_MSB)) << 16;
+ tmp |= readw(SPI_REG(REG_RX_LSB));
+ printd("data_in=0x%08x ", tmp);
+
+ if (bitlen <= 8)
+ *(uint8_t *)din = tmp & 0xff;
+ else if (bitlen <= 16)
+ *(uint16_t *)din = tmp & 0xffff;
+ else
+ *(uint32_t *)din = tmp;
+ }
+ dputchar('\n');
+
+ return 0;
+}
diff --git a/src/target/firmware/calypso/timer.c b/src/target/firmware/calypso/timer.c
new file mode 100644
index 00000000..1dd55f26
--- /dev/null
+++ b/src/target/firmware/calypso/timer.c
@@ -0,0 +1,156 @@
+/* Calypso DBB internal Timer Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdio.h>
+#include <memory.h>
+#include <stdint.h>
+
+#include <defines.h>
+
+#include <calypso/timer.h>
+#include <calypso/irq.h>
+
+#define BASE_ADDR_TIMER 0xfffe3800
+#define TIMER2_OFFSET 0x3000
+
+#define TIMER_REG(n, m) (((n)-1) ? (BASE_ADDR_TIMER + TIMER2_OFFSET + (m)) : (BASE_ADDR_TIMER + (m)))
+
+enum timer_reg {
+ CNTL_TIMER = 0x00,
+ LOAD_TIMER = 0x02,
+ READ_TIMER = 0x04,
+};
+
+enum timer_ctl {
+ CNTL_START = (1 << 0),
+ CNTL_AUTO_RELOAD = (1 << 1),
+ CNTL_CLOCK_ENABLE = (1 << 5),
+};
+
+/* Regular Timers (1 and 2) */
+
+void hwtimer_enable(int num, int on)
+{
+ uint8_t ctl;
+
+ if (num < 1 || num > 2) {
+ printf("Unknown timer %u\n", num);
+ return;
+ }
+
+ ctl = readb(TIMER_REG(num, CNTL_TIMER));
+ if (on)
+ ctl |= CNTL_START|CNTL_CLOCK_ENABLE;
+ else
+ ctl &= ~CNTL_START;
+ writeb(ctl, TIMER_REG(num, CNTL_TIMER));
+}
+
+void hwtimer_config(int num, uint8_t pre_scale, int auto_reload)
+{
+ uint8_t ctl;
+
+ ctl = (pre_scale & 0x7) << 2;
+ if (auto_reload)
+ ctl |= CNTL_AUTO_RELOAD;
+
+ writeb(ctl, TIMER_REG(num, CNTL_TIMER));
+}
+
+void hwtimer_load(int num, uint16_t val)
+{
+ writew(val, TIMER_REG(num, LOAD_TIMER));
+}
+
+uint16_t hwtimer_read(int num)
+{
+ uint8_t ctl = readb(TIMER_REG(num, CNTL_TIMER));
+
+ /* somehow a read results in an abort */
+ if ((ctl & (CNTL_START|CNTL_CLOCK_ENABLE)) != (CNTL_START|CNTL_CLOCK_ENABLE))
+ return 0xFFFF;
+ return readw(TIMER_REG(num, READ_TIMER));
+}
+
+void hwtimer_init(void)
+{
+ writeb(CNTL_CLOCK_ENABLE, TIMER_REG(1, CNTL_TIMER));
+ writeb(CNTL_CLOCK_ENABLE, TIMER_REG(2, CNTL_TIMER));
+}
+
+/* Watchdog Timer */
+
+#define BASE_ADDR_WDOG 0xfffff800
+#define WDOG_REG(m) (BASE_ADDR_WDOG + m)
+
+enum wdog_reg {
+ WD_CNTL_TIMER = CNTL_TIMER,
+ WD_LOAD_TIMER = LOAD_TIMER,
+ WD_READ_TIMER = 0x02,
+ WD_MODE = 0x04,
+};
+
+enum wdog_ctl {
+ WD_CTL_START = (1 << 7),
+ WD_CTL_AUTO_RELOAD = (1 << 8)
+};
+
+enum wdog_mode {
+ WD_MODE_DIS_ARM = 0xF5,
+ WD_MODE_DIS_CONFIRM = 0xA0,
+ WD_MODE_ENABLE = (1 << 15)
+};
+
+#define WD_CTL_PRESCALE(value) (((value)&0x07) << 9)
+
+static void wdog_irq(__unused enum irq_nr nr)
+{
+ puts("=> WATCHDOG\n");
+}
+
+void wdog_enable(int on)
+{
+ if (on) {
+ irq_config(IRQ_WATCHDOG, 0, 0, 0);
+ irq_register_handler(IRQ_WATCHDOG, &wdog_irq);
+ irq_enable(IRQ_WATCHDOG);
+ writew(WD_MODE_ENABLE, WDOG_REG(WD_MODE));
+ } else {
+ writew(WD_MODE_DIS_ARM, WDOG_REG(WD_MODE));
+ writew(WD_MODE_DIS_CONFIRM, WDOG_REG(WD_MODE));
+ }
+}
+
+void wdog_reset(void)
+{
+#if 0
+ // XXX: this is supposed to reset immediately but does not seem to
+ writew(0xF5, WDOG_REG(WD_MODE));
+ writew(0xFF, WDOG_REG(WD_MODE));
+#else
+ // enable watchdog
+ writew(WD_MODE_ENABLE, WDOG_REG(WD_MODE));
+ // force expiration
+ writew(0x0000, WDOG_REG(WD_LOAD_TIMER));
+ writew(0x0000, WDOG_REG(WD_LOAD_TIMER));
+#endif
+}
diff --git a/src/target/firmware/calypso/tpu.c b/src/target/firmware/calypso/tpu.c
new file mode 100644
index 00000000..0b60292a
--- /dev/null
+++ b/src/target/firmware/calypso/tpu.c
@@ -0,0 +1,346 @@
+/* Calypso DBB internal TPU (Time Processing Unit) Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <delay.h>
+#include <memory.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+
+/* Using TPU_DEBUG you will send special HLDC messages to the host PC
+ * containing the full TPU RAM content at the time you call tpu_enable() */
+//#define TPU_DEBUG
+
+#define BASE_ADDR_TPU 0xffff1000
+#define TPU_REG(x) (BASE_ADDR_TPU+(x))
+
+#define BASE_ADDR_TPU_RAM 0xffff9000
+#define TPU_RAM_END 0xffff97ff
+
+enum tpu_reg_arm {
+ TPU_CTRL = 0x0, /* Control & Status Register */
+ INT_CTRL = 0x2, /* Interrupt Control Register */
+ INT_STAT = 0x4, /* Interrupt Status Register */
+ TPU_OFFSET = 0xC, /* Offset operand value register */
+ TPU_SYNCHRO = 0xE, /* synchro operand value register */
+ IT_DSP_PG = 0x20,
+};
+
+enum tpu_ctrl_bits {
+ TPU_CTRL_RESET = (1 << 0),
+ TPU_CTRL_PAGE = (1 << 1),
+ TPU_CTRL_EN = (1 << 2),
+ /* unused */
+ TPU_CTRL_DSP_EN = (1 << 4),
+ /* unused */
+ TPU_CTRL_MCU_RAM_ACC = (1 << 6),
+ TPU_CTRL_TSP_RESET = (1 << 7),
+ TPU_CTRL_IDLE = (1 << 8),
+ TPU_CTRL_WAIT = (1 << 9),
+ TPU_CTRL_CK_ENABLE = (1 << 10),
+ TPU_CTRL_FULL_WRITE = (1 << 11),
+};
+
+enum tpu_int_ctrl_bits {
+ ICTRL_MCU_FRAME = (1 << 0),
+ ICTRL_MCU_PAGE = (1 << 1),
+ ICTRL_DSP_FRAME = (1 << 2),
+ ICTRL_DSP_FRAME_FORCE = (1 << 3),
+};
+
+static uint16_t *tpu_ptr = (uint16_t *)BASE_ADDR_TPU_RAM;
+
+#ifdef TPU_DEBUG
+#include <comm/sercomm.h>
+#include <layer1/sync.h>
+static void tpu_ram_read_en(int enable)
+{
+ uint16_t reg;
+
+ reg = readw(TPU_REG(TPU_CTRL));
+ if (enable)
+ reg |= TPU_CTRL_MCU_RAM_ACC;
+ else
+ reg &= ~TPU_CTRL_MCU_RAM_ACC;
+ writew(reg, TPU_REG(TPU_CTRL));
+}
+
+static void tpu_debug(void)
+{
+ uint16_t *tpu_base = (uint16_t *)BASE_ADDR_TPU_RAM;
+ unsigned int tpu_size = tpu_ptr - tpu_base;
+ struct msgb *msg = sercomm_alloc_msgb(tpu_size*2);
+ uint16_t *data;
+ uint32_t *fn;
+ uint16_t reg;
+ int i;
+
+ /* prepend tpu memory dump with frame number */
+ fn = (uint32_t *) msgb_put(msg, sizeof(fn));
+ *fn = l1s.current_time.fn;
+
+ tpu_ram_read_en(1);
+
+ data = (uint16_t *) msgb_put(msg, tpu_size*2);
+ for (i = 0; i < tpu_size; i ++)
+ data[i] = tpu_base[i];
+
+ tpu_ram_read_en(0);
+
+ sercomm_sendmsg(SC_DLCI_DEBUG, msg);
+}
+#else
+static void tpu_debug(void) { }
+#endif
+
+#define BIT_SET 1
+#define BIT_CLEAR 0
+
+/* wait for a certain control bit to be set */
+static int tpu_wait_ctrl_bit(uint16_t bit, int set)
+{
+ int timeout = 10*1000;
+
+ while (1) {
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+ if (set) {
+ if (reg & bit)
+ break;
+ } else {
+ if (!(reg & bit))
+ break;
+ }
+ timeout--;
+ if (timeout <= 0) {
+ puts("Timeout while waiting for TPU ctrl bit!\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* assert or de-assert TPU reset */
+void tpu_reset(int active)
+{
+ uint16_t reg;
+
+ printd("tpu_reset(%u)\n", active);
+ reg = readw(TPU_REG(TPU_CTRL));
+ if (active) {
+ reg |= (TPU_CTRL_RESET|TPU_CTRL_TSP_RESET);
+ writew(reg, TPU_REG(TPU_CTRL));
+ tpu_wait_ctrl_bit(TPU_CTRL_RESET, BIT_SET);
+ } else {
+ reg &= ~(TPU_CTRL_RESET|TPU_CTRL_TSP_RESET);
+ writew(reg, TPU_REG(TPU_CTRL));
+ tpu_wait_ctrl_bit(TPU_CTRL_RESET, BIT_CLEAR);
+ }
+}
+
+/* Enable or Disable a new scenario loaded into the TPU */
+void tpu_enable(int active)
+{
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+
+ printd("tpu_enable(%u)\n", active);
+
+ tpu_debug();
+
+ if (active)
+ reg |= TPU_CTRL_EN;
+ else
+ reg &= ~TPU_CTRL_EN;
+ writew(reg, TPU_REG(TPU_CTRL));
+
+ /* After the new scenario is loaded, TPU switches the MCU-visible memory
+ * page, i.e. we can write without any danger */
+ tpu_rewind();
+#if 0
+ {
+ int i;
+ uint16_t oldreg = 0;
+
+ for (i = 0; i < 100000; i++) {
+ reg = readw(TPU_REG(TPU_CTRL));
+ if (i == 0 || oldreg != reg) {
+ printd("%d TPU state: 0x%04x\n", i, reg);
+ }
+ oldreg = reg;
+ }
+ }
+#endif
+}
+
+/* Enable or Disable the clock of the TPU Module */
+void tpu_clk_enable(int active)
+{
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+
+ printd("tpu_clk_enable(%u)\n", active);
+ if (active) {
+ reg |= TPU_CTRL_CK_ENABLE;
+ writew(reg, TPU_REG(TPU_CTRL));
+ tpu_wait_ctrl_bit(TPU_CTRL_CK_ENABLE, BIT_SET);
+ } else {
+ reg &= ~TPU_CTRL_CK_ENABLE;
+ writew(reg, TPU_REG(TPU_CTRL));
+ tpu_wait_ctrl_bit(TPU_CTRL_CK_ENABLE, BIT_CLEAR);
+ }
+}
+
+/* Enable Frame Interrupt generation on next frame. DSP will reset it */
+void tpu_dsp_frameirq_enable(void)
+{
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+ reg |= TPU_CTRL_DSP_EN;
+ writew(reg, TPU_REG(TPU_CTRL));
+
+ tpu_wait_ctrl_bit(TPU_CTRL_DSP_EN, BIT_SET);
+}
+
+/* Is a Frame interrupt still pending for the DSP ? */
+int tpu_dsp_fameirq_pending(void)
+{
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+
+ if (reg & TPU_CTRL_DSP_EN)
+ return 1;
+
+ return 0;
+}
+
+void tpu_rewind(void)
+{
+ dputs("tpu_rewind()\n");
+ tpu_ptr = (uint16_t *) BASE_ADDR_TPU_RAM;
+}
+
+void tpu_enqueue(uint16_t instr)
+{
+ printd("tpu_enqueue(tpu_ptr=%p, instr=0x%04x)\n", tpu_ptr, instr);
+ *tpu_ptr++ = instr;
+ if (tpu_ptr > (uint16_t *) TPU_RAM_END)
+ puts("TPU enqueue beyond end of TPU memory\n");
+}
+
+void tpu_init(void)
+{
+ uint16_t *ptr;
+
+ /* Put TPU into Reset and enable clock */
+ tpu_reset(1);
+ tpu_clk_enable(1);
+
+ /* set all TPU RAM to zero */
+ for (ptr = (uint16_t *) BASE_ADDR_TPU_RAM; ptr < (uint16_t *) TPU_RAM_END; ptr++)
+ *ptr = 0x0000;
+
+ /* Get TPU out of reset */
+ tpu_reset(0);
+ /* Disable all interrupts */
+ writeb(0x7, TPU_REG(INT_CTRL));
+
+ tpu_rewind();
+ tpu_enq_offset(0);
+ tpu_enq_sync(0);
+}
+
+void tpu_test(void)
+{
+ int i;
+
+ /* program a sequence of TSPACT events into the TPU */
+ for (i = 0; i < 10; i++) {
+ puts("TSP ACT enable: ");
+ tsp_act_enable(0x0001);
+ tpu_enq_wait(10);
+ puts("TSP ACT disable: ");
+ tsp_act_disable(0x0001);
+ tpu_enq_wait(10);
+ }
+ tpu_enq_sleep();
+
+ /* tell the chip to execute the scenario */
+ tpu_enable(1);
+}
+
+void tpu_wait_idle(void)
+{
+ dputs("Waiting for TPU Idle ");
+ /* Wait until TPU is doing something */
+ delay_us(3);
+ /* Wait until TPU is idle */
+ while (readw(TPU_REG(TPU_CTRL)) & TPU_CTRL_IDLE)
+ dputchar('.');
+ dputs("Done!\n");
+}
+
+void tpu_frame_irq_en(int mcu, int dsp)
+{
+ uint8_t reg = readb(TPU_REG(INT_CTRL));
+ if (mcu)
+ reg &= ~ICTRL_MCU_FRAME;
+ else
+ reg |= ICTRL_MCU_FRAME;
+
+ if (dsp)
+ reg &= ~ICTRL_DSP_FRAME;
+ else
+ reg |= ICTRL_DSP_FRAME;
+
+ writeb(reg, TPU_REG(INT_CTRL));
+}
+
+void tpu_force_dsp_frame_irq(void)
+{
+ uint8_t reg = readb(TPU_REG(INT_CTRL));
+ reg |= ICTRL_DSP_FRAME_FORCE;
+ writeb(reg, TPU_REG(INT_CTRL));
+}
+
+uint16_t tpu_get_offset(void)
+{
+ return readw(TPU_REG(TPU_OFFSET));
+}
+
+uint16_t tpu_get_synchro(void)
+{
+ return readw(TPU_REG(TPU_SYNCHRO));
+}
+
+/* add two numbers, modulo 5000, and ensure the result is positive */
+uint16_t add_mod5000(int16_t a, int16_t b)
+{
+ int32_t sum = (int32_t)a + (int32_t)b;
+
+ sum %= 5000;
+
+ /* wrap around zero */
+ if (sum < 0)
+ sum += 5000;
+
+ return sum;
+}
diff --git a/src/target/firmware/calypso/tsp.c b/src/target/firmware/calypso/tsp.c
new file mode 100644
index 00000000..5d24f48e
--- /dev/null
+++ b/src/target/firmware/calypso/tsp.c
@@ -0,0 +1,121 @@
+/* Calypso DBB internal TSP (Time Serial Port) Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+
+static uint16_t tspact_state;
+
+/* initiate a TSP write through the TPU */
+void tsp_write(uint8_t dev_idx, uint8_t bitlen, uint32_t dout)
+{
+ if (bitlen <= 8) {
+ tpu_enq_move(TPUI_TX_1, dout & 0xff);
+ } else if (bitlen <= 16) {
+ tpu_enq_move(TPUI_TX_1, (dout >> 8) & 0xff);
+ tpu_enq_move(TPUI_TX_2, dout & 0xff);
+ } else if (bitlen <= 24) {
+ tpu_enq_move(TPUI_TX_1, (dout >> 16) & 0xff);
+ tpu_enq_move(TPUI_TX_2, (dout >> 8) & 0xff);
+ tpu_enq_move(TPUI_TX_3, dout & 0xff);
+ } else {
+ tpu_enq_move(TPUI_TX_1, (dout >> 24) & 0xff);
+ tpu_enq_move(TPUI_TX_2, (dout >> 16) & 0xff);
+ tpu_enq_move(TPUI_TX_3, (dout >> 8) & 0xff);
+ tpu_enq_move(TPUI_TX_4, dout & 0xff);
+ }
+ tpu_enq_move(TPUI_TSP_CTRL1, (dev_idx << 5) | (bitlen - 1));
+ tpu_enq_move(TPUI_TSP_CTRL2, TPUI_CTRL2_WR);
+}
+
+/* Configure clock edge and chip enable polarity for a device */
+void tsp_setup(uint8_t dev_idx, int clk_rising, int en_positive, int en_edge)
+{
+ uint8_t reg = TPUI_TSP_SET1 + (dev_idx / 2);
+ uint8_t val = 0;
+ uint8_t shift;
+
+ if (dev_idx & 1)
+ shift = 4;
+ else
+ shift = 0;
+
+ if (clk_rising)
+ val |= 1;
+ if (en_positive)
+ val |= 2;
+ if (en_edge)
+ val |= 4;
+
+ tpu_enq_move(reg, (val << shift));
+}
+
+/* Update the TSPACT state, including enable and disable */
+void tsp_act_update(uint16_t new_act)
+{
+ uint8_t low = new_act & 0xff;
+ uint8_t high = new_act >> 8;
+
+ if (low != (tspact_state & 0xff))
+ tpu_enq_move(TPUI_TSP_ACT_L, low);
+ if (high != (tspact_state >> 8))
+ tpu_enq_move(TPUI_TSP_ACT_U, high);
+
+ tspact_state = new_act;
+}
+
+/* Enable one or multiple TSPACT signals */
+void tsp_act_enable(uint16_t bitmask)
+{
+ uint16_t new_act = tspact_state | bitmask;
+ tsp_act_update(new_act);
+}
+
+/* Disable one or multiple TSPACT signals */
+void tsp_act_disable(uint16_t bitmask)
+{
+ uint16_t new_act = tspact_state & ~bitmask;
+ tsp_act_update(new_act);
+}
+
+/* Obtain the current tspact state */
+uint16_t tsp_act_state(void)
+{
+ return tspact_state;
+}
+
+/* Toggle one or multiple TSPACT signals */
+void tsp_act_toggle(uint16_t bitmask)
+{
+ uint16_t new_act = tspact_state ^ bitmask;
+ tsp_act_update(new_act);
+}
+
+void tsp_init(void)
+{
+ tsp_act_update(0);
+}
diff --git a/src/target/firmware/calypso/uart.c b/src/target/firmware/calypso/uart.c
new file mode 100644
index 00000000..bcb56bd0
--- /dev/null
+++ b/src/target/firmware/calypso/uart.c
@@ -0,0 +1,440 @@
+/* Calypso DBB internal UART Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <debug.h>
+
+#include <memory.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <defines.h>
+#include <console.h>
+#include <comm/sercomm.h>
+
+#include <calypso/irq.h>
+#include <uart.h>
+
+#define BASE_ADDR_UART_MODEM 0xffff5000
+#define OFFSET_IRDA 0x800
+
+#define UART_REG(n,m) (BASE_ADDR_UART_MODEM + ((n)*OFFSET_IRDA)+(m))
+
+#define LCR7BIT 0x80
+#define LCRBFBIT 0x40
+#define MCR6BIT 0x20
+#define REG_OFFS(m) ((m) & ~(LCR7BIT|LCRBFBIT|MCR6BIT))
+/* read access LCR[7] = 0 */
+enum uart_reg {
+ RHR = 0,
+ IER = 1,
+ IIR = 2,
+ LCR = 3,
+ MCR = 4,
+ LSR = 5,
+ MSR = 6,
+ SPR = 7,
+ MDR1 = 8,
+ DMR2 = 9,
+ SFLSR = 0x0a,
+ RESUME = 0x0b,
+ SFREGL = 0x0c,
+ SFREGH = 0x0d,
+ BLR = 0x0e,
+ ACREG = 0x0f,
+ SCR = 0x10,
+ SSR = 0x11,
+ EBLR = 0x12,
+/* read access LCR[7] = 1 */
+ DLL = RHR | LCR7BIT,
+ DLH = IER | LCR7BIT,
+ DIV1_6 = ACREG | LCR7BIT,
+/* read/write access LCR[7:0] = 0xbf */
+ EFR = IIR | LCRBFBIT,
+ XON1 = MCR | LCRBFBIT,
+ XON2 = LSR | LCRBFBIT,
+ XOFF1 = MSR | LCRBFBIT,
+ XOFF2 = SPR | LCRBFBIT,
+/* read/write access if EFR[4] = 1 and MCR[6] = 1 */
+ TCR = MSR | MCR6BIT,
+ TLR = SPR | MCR6BIT,
+};
+/* write access LCR[7] = 0 */
+#define THR RHR
+#define FCR IIR /* only if EFR[4] = 1 */
+#define TXFLL SFLSR
+#define TXFLH RESUME
+#define RXFLL SFREGL
+#define RXFLH SFREGH
+
+enum fcr_bits {
+ FIFO_EN = (1 << 0),
+ RX_FIFO_CLEAR = (1 << 1),
+ TX_FIFO_CLEAR = (1 << 2),
+ DMA_MODE = (1 << 3),
+};
+#define TX_FIFO_TRIG_SHIFT 4
+#define RX_FIFO_TRIG_SHIFT 6
+
+enum iir_bits {
+ IIR_INT_PENDING = 0x01,
+ IIR_INT_TYPE = 0x3E,
+ IIR_INT_TYPE_RX_STATUS_ERROR = 0x06,
+ IIR_INT_TYPE_RX_TIMEOUT = 0x0C,
+ IIR_INT_TYPE_RHR = 0x04,
+ IIR_INT_TYPE_THR = 0x02,
+ IIR_INT_TYPE_MSR = 0x00,
+ IIR_INT_TYPE_XOFF = 0x10,
+ IIR_INT_TYPE_FLOW = 0x20,
+ IIR_FCR0_MIRROR = 0xC0,
+};
+
+#define UART_REG_UIR 0xffff6000
+
+/* enable or disable the divisor latch for access to DLL, DLH */
+static void uart_set_lcr7bit(int uart, int on)
+{
+ uint8_t reg;
+
+ reg = readb(UART_REG(uart, LCR));
+ if (on)
+ reg |= (1 << 7);
+ else
+ reg &= ~(1 << 7);
+ writeb(reg, UART_REG(uart, LCR));
+}
+
+static uint8_t old_lcr;
+static void uart_set_lcr_bf(int uart, int on)
+{
+ if (on) {
+ old_lcr = readb(UART_REG(uart, LCR));
+ writeb(0xBF, UART_REG(uart, LCR));
+ } else {
+ writeb(old_lcr, UART_REG(uart, LCR));
+ }
+}
+
+/* Enable or disable the TCR_TLR latch bit in MCR[6] */
+static void uart_set_mcr6bit(int uart, int on)
+{
+ uint8_t mcr;
+ /* we assume EFR[4] is always set to 1 */
+ mcr = readb(UART_REG(uart, MCR));
+ if (on)
+ mcr |= (1 << 6);
+ else
+ mcr &= ~(1 << 6);
+ writeb(mcr, UART_REG(uart, MCR));
+}
+
+static void uart_reg_write(int uart, enum uart_reg reg, uint8_t val)
+{
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 1);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 1);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 1);
+
+ writeb(val, UART_REG(uart, REG_OFFS(reg)));
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 0);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 0);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 0);
+}
+
+/* read from a UART register, applying any required latch bits */
+static uint8_t uart_reg_read(int uart, enum uart_reg reg)
+{
+ uint8_t ret;
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 1);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 1);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 1);
+
+ ret = readb(UART_REG(uart, REG_OFFS(reg)));
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 0);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 0);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 0);
+
+ return ret;
+}
+
+static void uart_irq_handler_cons(__unused enum irq_nr irqnr)
+{
+ const uint8_t uart = CONS_UART_NR;
+ uint8_t iir;
+
+ //uart_putchar_nb(uart, 'U');
+
+ iir = uart_reg_read(uart, IIR);
+ if (iir & IIR_INT_PENDING)
+ return;
+
+ switch (iir & IIR_INT_TYPE) {
+ case IIR_INT_TYPE_RHR:
+ break;
+ case IIR_INT_TYPE_THR:
+ if (cons_rb_flush() == 1) {
+ /* everything was flushed, disable THR IRQ */
+ uint8_t ier = uart_reg_read(uart, IER);
+ ier &= ~(1 << 1);
+ uart_reg_write(uart, IER, ier);
+ }
+ break;
+ case IIR_INT_TYPE_MSR:
+ break;
+ case IIR_INT_TYPE_RX_STATUS_ERROR:
+ break;
+ case IIR_INT_TYPE_RX_TIMEOUT:
+ break;
+ case IIR_INT_TYPE_XOFF:
+ break;
+ }
+}
+
+static void uart_irq_handler_sercomm(__unused enum irq_nr irqnr)
+{
+ const uint8_t uart = SERCOMM_UART_NR;
+ uint8_t iir, ch;
+
+ //uart_putchar_nb(uart, 'U');
+
+ iir = uart_reg_read(uart, IIR);
+ if (iir & IIR_INT_PENDING)
+ return;
+
+ switch (iir & IIR_INT_TYPE) {
+ case IIR_INT_TYPE_RX_TIMEOUT:
+ case IIR_INT_TYPE_RHR:
+ /* as long as we have rx data available */
+ while (uart_getchar_nb(uart, &ch)) {
+ if (sercomm_drv_rx_char(ch) < 0) {
+ /* sercomm cannot receive more data right now */
+ uart_irq_enable(uart, UART_IRQ_RX_CHAR, 0);
+ }
+ }
+ break;
+ case IIR_INT_TYPE_THR:
+ /* as long as we have space in the FIFO */
+ while (!uart_tx_busy(uart)) {
+ /* get a byte from sercomm */
+ if (!sercomm_drv_pull(&ch)) {
+ /* no more bytes in sercomm, stop TX interrupts */
+ uart_irq_enable(uart, UART_IRQ_TX_EMPTY, 0);
+ break;
+ }
+ /* write the byte into the TX FIFO */
+ uart_putchar_nb(uart, ch);
+ }
+ break;
+ case IIR_INT_TYPE_MSR:
+ printf("UART IRQ MSR\n");
+ break;
+ case IIR_INT_TYPE_RX_STATUS_ERROR:
+ printf("UART IRQ RX_SE\n");
+ break;
+ case IIR_INT_TYPE_XOFF:
+ printf("UART IRQXOFF\n");
+ break;
+ }
+}
+
+static const uint8_t uart2irq[] = {
+ [0] = IRQ_UART_IRDA,
+ [1] = IRQ_UART_MODEM,
+};
+
+void uart_init(uint8_t uart, uint8_t interrupts)
+{
+ uint8_t irq = uart2irq[uart];
+
+ uart_reg_write(uart, IER, 0x00);
+ if (uart == CONS_UART_NR) {
+ cons_init();
+ if(interrupts) {
+ irq_register_handler(irq, &uart_irq_handler_cons);
+ irq_config(irq, 0, 0, 0xff);
+ irq_enable(irq);
+ }
+ } else {
+ sercomm_init();
+ if(interrupts) {
+ irq_register_handler(irq, &uart_irq_handler_sercomm);
+ irq_config(irq, 0, 0, 0xff);
+ irq_enable(irq);
+ }
+ uart_irq_enable(uart, UART_IRQ_RX_CHAR, 1);
+ }
+#if 0
+ if (uart == 1) {
+ /* assign UART to MCU and unmask interrupts*/
+ writeb(UART_REG_UIR, 0x00);
+ }
+#endif
+
+ /* if we don't initialize these, we get strange corruptions in the
+ received data... :-( */
+ uart_reg_write(uart, MDR1, 0x07); /* turn off UART */
+ uart_reg_write(uart, XON1, 0x00); /* Xon1/Addr Register */
+ uart_reg_write(uart, XON2, 0x00); /* Xon2/Addr Register */
+ uart_reg_write(uart, XOFF1, 0x00); /* Xoff1 Register */
+ uart_reg_write(uart, XOFF2, 0x00); /* Xoff2 Register */
+ uart_reg_write(uart, EFR, 0x00); /* Enhanced Features Register */
+
+ /* select UART mode */
+ uart_reg_write(uart, MDR1, 0);
+ /* no XON/XOFF flow control, ENHANCED_EN, no auto-RTS/CTS */
+ uart_reg_write(uart, EFR, (1 << 4));
+ /* enable Tx/Rx FIFO, Tx trigger at 56 spaces, Rx trigger at 60 chars */
+ uart_reg_write(uart, FCR, FIFO_EN | RX_FIFO_CLEAR | TX_FIFO_CLEAR |
+ (3 << TX_FIFO_TRIG_SHIFT) | (3 << RX_FIFO_TRIG_SHIFT));
+
+ /* THR interrupt only when TX FIFO and TX shift register are empty */
+ uart_reg_write(uart, SCR, (1 << 0));// | (1 << 3));
+
+ /* 8 bit, 1 stop bit, no parity, no break */
+ uart_reg_write(uart, LCR, 0x03);
+
+ uart_set_lcr7bit(uart, 0);
+}
+
+void uart_poll(uint8_t uart) {
+ if(uart == CONS_UART_NR) {
+ uart_irq_handler_cons(0);
+ } else {
+ uart_irq_handler_sercomm(0);
+ }
+}
+
+void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on)
+{
+ uint8_t ier = uart_reg_read(uart, IER);
+ uint8_t mask = 0;
+
+ switch (irq) {
+ case UART_IRQ_TX_EMPTY:
+ mask = (1 << 1);
+ break;
+ case UART_IRQ_RX_CHAR:
+ mask = (1 << 0);
+ break;
+ }
+
+ if (on)
+ ier |= mask;
+ else
+ ier &= ~mask;
+
+ uart_reg_write(uart, IER, ier);
+}
+
+
+void uart_putchar_wait(uint8_t uart, int c)
+{
+ /* wait while TX FIFO indicates full */
+ while (readb(UART_REG(uart, SSR)) & 0x01) { }
+
+ /* put character in TX FIFO */
+ writeb(c, UART_REG(uart, THR));
+}
+
+int uart_putchar_nb(uint8_t uart, int c)
+{
+ /* if TX FIFO indicates full, abort */
+ if (readb(UART_REG(uart, SSR)) & 0x01)
+ return 0;
+
+ writeb(c, UART_REG(uart, THR));
+ return 1;
+}
+
+int uart_getchar_nb(uint8_t uart, uint8_t *ch)
+{
+ uint8_t lsr;
+
+ lsr = readb(UART_REG(uart, LSR));
+
+ /* something strange happened */
+ if (lsr & 0x02)
+ printf("LSR RX_OE\n");
+ if (lsr & 0x04)
+ printf("LSR RX_PE\n");
+ if (lsr & 0x08)
+ printf("LSR RX_FE\n");
+ if (lsr & 0x10)
+ printf("LSR RX_BI\n");
+ if (lsr & 0x80)
+ printf("LSR RX_FIFO_STS\n");
+
+ /* is the Rx FIFO empty? */
+ if (!(lsr & 0x01))
+ return 0;
+
+ *ch = readb(UART_REG(uart, RHR));
+ //printf("getchar_nb(%u) = %02x\n", uart, *ch);
+ return 1;
+}
+
+int uart_tx_busy(uint8_t uart)
+{
+ if (readb(UART_REG(uart, SSR)) & 0x01)
+ return 1;
+ return 0;
+}
+
+static const uint16_t divider[] = {
+ [UART_38400] = 21, /* 38,690 */
+ [UART_57600] = 14, /* 58,035 */
+ [UART_115200] = 7, /* 116,071 */
+ [UART_230400] = 4, /* 203,125! (-3% would be 223,488) */
+ [UART_460800] = 2, /* 406,250! (-3% would be 446,976) */
+ [UART_921600] = 1, /* 812,500! (-3% would be 893,952) */
+};
+
+int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt)
+{
+ uint16_t div;
+
+ if (bdrt >= ARRAY_SIZE(divider))
+ return -1;
+
+ div = divider[bdrt];
+ uart_set_lcr7bit(uart, 1);
+ writeb(div & 0xff, UART_REG(uart, DLL));
+ writeb(div >> 8, UART_REG(uart, DLH));
+ uart_set_lcr7bit(uart, 0);
+
+ return 0;
+}
diff --git a/src/target/firmware/calypso/uwire.c b/src/target/firmware/calypso/uwire.c
new file mode 100644
index 00000000..ac8f15e4
--- /dev/null
+++ b/src/target/firmware/calypso/uwire.c
@@ -0,0 +1,136 @@
+/* Driver for uWire Master Controller inside TI Calypso */
+
+/* (C) 2010 by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+//#define DEBUG
+#include <debug.h>
+
+#include <memory.h>
+#include <uwire.h>
+#include <delay.h>
+
+#define BASE_ADDR_UWIRE 0xfffe4000
+#define UWIRE_REG(n) (BASE_ADDR_UWIRE+(n))
+
+enum uwire_regs {
+ REG_DATA = 0x00,
+ REG_CSR = 0x02,
+ REG_SR1 = 0x04,
+ REG_SR2 = 0x06,
+ REG_SR3 = 0x08,
+};
+
+#define UWIRE_CSR_BITS_RD(n) (((n) & 0x1f) << 0)
+#define UWIRE_CSR_BITS_WR(n) (((n) & 0x1f) << 5)
+#define UWIRE_CSR_IDX(n) (((n) & 3) << 10)
+#define UWIRE_CSR_CS_CMD (1 << 12)
+#define UWIRE_CSR_START (1 << 13)
+#define UWIRE_CSR_CSRB (1 << 14)
+#define UWIRE_CSR_RDRB (1 << 15)
+
+#define UWIRE_CSn_EDGE_RD (1 << 0) /* 1=falling 0=rising */
+#define UWIRE_CSn_EDGE_WR (1 << 1) /* 1=falling 0=rising */
+#define UWIRE_CSn_CS_LVL (1 << 2)
+#define UWIRE_CSn_FRQ_DIV2 (0 << 3)
+#define UWIRE_CSn_FRQ_DIV4 (1 << 3)
+#define UWIRE_CSn_FRQ_DIV8 (2 << 3)
+#define UWIRE_CSn_CKH
+
+#define UWIRE_CSn_SHIFT(n) (((n) & 1) ? 6 : 0)
+#define UWIRE_CSn_REG(n) (((n) & 2) ? REG_SR2 : REG_SR1)
+
+#define UWIRE_SR3_CLK_EN (1 << 0)
+#define UWIRE_SR3_CLK_DIV2 (0 << 1)
+#define UWIRE_SR3_CLK_DIV4 (1 << 1)
+#define UWIRE_SR3_CLK_DIV7 (2 << 1)
+#define UWIRE_SR3_CLK_DIV10 (3 << 1)
+
+static inline void _uwire_wait(int mask, int val)
+{
+ while ((readw(UWIRE_REG(REG_CSR)) & mask) != val);
+}
+
+void uwire_init(void)
+{
+ writew(UWIRE_SR3_CLK_EN | UWIRE_SR3_CLK_DIV2, UWIRE_REG(REG_SR3));
+ /* FIXME only init CS0 for now */
+ writew(((UWIRE_CSn_CS_LVL | UWIRE_CSn_FRQ_DIV2) << UWIRE_CSn_SHIFT(0)),
+ UWIRE_REG(UWIRE_CSn_REG(0)));
+ writew(UWIRE_CSR_IDX(0) | UWIRE_CSR_CS_CMD, UWIRE_REG(REG_CSR));
+ _uwire_wait(UWIRE_CSR_CSRB, 0);
+}
+
+int uwire_xfer(int cs, int bitlen, const void *dout, void *din)
+{
+ uint16_t tmp = 0;
+
+ if (bitlen <= 0 || bitlen > 16)
+ return -1;
+ if (cs < 0 || cs > 4)
+ return -1;
+
+ /* FIXME uwire_init always selects CS0 for now */
+
+ printd("uwire_xfer(dev_idx=%u, bitlen=%u\n", cs, bitlen);
+
+ /* select the chip */
+ writew(UWIRE_CSR_IDX(0) | UWIRE_CSR_CS_CMD, UWIRE_REG(REG_CSR));
+ _uwire_wait(UWIRE_CSR_CSRB, 0);
+
+ if (dout) {
+ if (bitlen <= 8)
+ tmp = *(uint8_t *)dout;
+ else if (bitlen <= 16)
+ tmp = *(uint16_t *)dout;
+ tmp <<= 16 - bitlen; /* align to MSB */
+ writew(tmp, UWIRE_REG(REG_DATA));
+ printd(", data_out=0x%04hx", tmp);
+ }
+
+ tmp = (dout ? UWIRE_CSR_BITS_WR(bitlen) : 0) |
+ (din ? UWIRE_CSR_BITS_RD(bitlen) : 0) |
+ UWIRE_CSR_START;
+ writew(tmp, UWIRE_REG(REG_CSR));
+
+ _uwire_wait(UWIRE_CSR_CSRB, 0);
+
+ if (din) {
+ _uwire_wait(UWIRE_CSR_RDRB, UWIRE_CSR_RDRB);
+
+ tmp = readw(UWIRE_REG(REG_DATA));
+ printd(", data_in=0x%08x", tmp);
+
+ if (bitlen <= 8)
+ *(uint8_t *)din = tmp & 0xff;
+ else if (bitlen <= 16)
+ *(uint16_t *)din = tmp & 0xffff;
+ }
+ /* unselect the chip */
+ writew(UWIRE_CSR_IDX(0) | 0, UWIRE_REG(REG_CSR));
+ _uwire_wait(UWIRE_CSR_CSRB, 0);
+
+ printd(")\n");
+
+ return 0;
+}
diff --git a/src/target/firmware/comm/Makefile b/src/target/firmware/comm/Makefile
new file mode 100644
index 00000000..25fbb983
--- /dev/null
+++ b/src/target/firmware/comm/Makefile
@@ -0,0 +1,5 @@
+
+LIBRARIES+=comm
+comm_DIR=comm
+comm_SRCS=msgb.c sercomm.c sercomm_cons.c timer.c
+
diff --git a/src/target/firmware/comm/msgb.c b/src/target/firmware/comm/msgb.c
new file mode 100644
index 00000000..3524ba58
--- /dev/null
+++ b/src/target/firmware/comm/msgb.c
@@ -0,0 +1,79 @@
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <asm/system.h>
+
+#include <debug.h>
+#include <delay.h>
+#include <console.h>
+
+#include <osmocom/core/msgb.h>
+
+#define NO_TALLOC
+
+void *tall_msgb_ctx;
+
+#ifdef NO_TALLOC
+/* This is a poor mans static allocator for msgb objects */
+#define MSGB_DATA_SIZE 256+4
+#define MSGB_NUM 32
+struct supermsg {
+ uint8_t allocated;
+ struct msgb msg;
+ uint8_t buf[MSGB_DATA_SIZE];
+};
+static struct supermsg msgs[MSGB_NUM];
+void *_talloc_zero(void *ctx, unsigned int size, const char *name)
+{
+ unsigned long flags;
+ unsigned int i;
+
+ local_firq_save(flags);
+
+ if (size > sizeof(struct msgb) + MSGB_DATA_SIZE)
+ goto panic;
+
+ for (i = 0; i < ARRAY_SIZE(msgs); i++) {
+ if (!msgs[i].allocated) {
+ msgs[i].allocated = 1;
+ memset(&msgs[i].msg, 0, sizeof(msgs[i].msg));
+ memset(&msgs[i].buf, 0, sizeof(msgs[i].buf));
+ local_irq_restore(flags);
+ return &msgs[i].msg;
+ }
+ }
+
+panic:
+ cons_puts("unable to allocate msgb\n");
+ while (1);
+
+ return NULL; /* not reached */
+}
+void talloc_free(void *msg)
+{
+ struct supermsg *smsg = container_of(msg, struct supermsg, msg);
+ /* no locking required, since this is atomic */
+ smsg->allocated = 0;
+}
+#endif
diff --git a/src/target/firmware/comm/sercomm.c b/src/target/firmware/comm/sercomm.c
new file mode 100644
index 00000000..ddc852ce
--- /dev/null
+++ b/src/target/firmware/comm/sercomm.c
@@ -0,0 +1,297 @@
+/* Serial communications layer, based on HDLC */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <osmocom/core/msgb.h>
+
+#ifdef HOST_BUILD
+
+# define SERCOMM_RX_MSG_SIZE 2048
+# ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+# endif
+# include <sercomm.h>
+
+static inline void sercomm_lock(unsigned long __attribute__((unused)) *flags) {}
+static inline void sercomm_unlock(unsigned long __attribute__((unused)) *flags) {}
+
+#else
+
+# define SERCOMM_RX_MSG_SIZE 256
+# include <debug.h>
+# include <osmocom/core/linuxlist.h>
+# include <asm/system.h>
+
+static inline void sercomm_lock(unsigned long *flags)
+{
+ local_firq_save(*flags);
+}
+
+static inline void sercomm_unlock(unsigned long *flags)
+{
+ local_irq_restore(*flags);
+}
+
+# include <comm/sercomm.h>
+# include <uart.h>
+
+#endif
+
+
+enum rx_state {
+ RX_ST_WAIT_START,
+ RX_ST_ADDR,
+ RX_ST_CTRL,
+ RX_ST_DATA,
+ RX_ST_ESCAPE,
+};
+
+static struct {
+ int initialized;
+
+ /* transmit side */
+ struct {
+ struct llist_head dlci_queues[_SC_DLCI_MAX];
+ struct msgb *msg;
+ enum rx_state state;
+ uint8_t *next_char;
+ } tx;
+
+ /* receive side */
+ struct {
+ dlci_cb_t dlci_handler[_SC_DLCI_MAX];
+ struct msgb *msg;
+ enum rx_state state;
+ uint8_t dlci;
+ uint8_t ctrl;
+ } rx;
+
+} sercomm;
+
+void sercomm_init(void)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(sercomm.tx.dlci_queues); i++)
+ INIT_LLIST_HEAD(&sercomm.tx.dlci_queues[i]);
+
+ sercomm.rx.msg = NULL;
+ sercomm.initialized = 1;
+
+ /* set up the echo dlci */
+ sercomm_register_rx_cb(SC_DLCI_ECHO, &sercomm_sendmsg);
+}
+
+int sercomm_initialized(void)
+{
+ return sercomm.initialized;
+}
+
+/* user interface for transmitting messages for a given DLCI */
+void sercomm_sendmsg(uint8_t dlci, struct msgb *msg)
+{
+ unsigned long flags;
+ uint8_t *hdr;
+
+ /* prepend address + control octet */
+ hdr = msgb_push(msg, 2);
+ hdr[0] = dlci;
+ hdr[1] = HDLC_C_UI;
+
+ /* This functiion can be called from any context: FIQ, IRQ
+ * and supervisor context. Proper locking is important! */
+ sercomm_lock(&flags);
+ msgb_enqueue(&sercomm.tx.dlci_queues[dlci], msg);
+ sercomm_unlock(&flags);
+
+#ifndef HOST_BUILD
+ /* tell UART that we have something to send */
+ uart_irq_enable(SERCOMM_UART_NR, UART_IRQ_TX_EMPTY, 1);
+#endif
+}
+
+/* how deep is the Tx queue for a given DLCI */
+unsigned int sercomm_tx_queue_depth(uint8_t dlci)
+{
+ struct llist_head *le;
+ unsigned int num = 0;
+
+ llist_for_each(le, &sercomm.tx.dlci_queues[dlci]) {
+ num++;
+ }
+
+ return num;
+}
+
+/* fetch one octet of to-be-transmitted serial data */
+int sercomm_drv_pull(uint8_t *ch)
+{
+ unsigned long flags;
+
+ /* we may be called from interrupt context, but we stiff need to lock
+ * because sercomm could be accessed from a FIQ context ... */
+
+ sercomm_lock(&flags);
+
+ if (!sercomm.tx.msg) {
+ unsigned int i;
+ /* dequeue a new message from the queues */
+ for (i = 0; i < ARRAY_SIZE(sercomm.tx.dlci_queues); i++) {
+ sercomm.tx.msg = msgb_dequeue(&sercomm.tx.dlci_queues[i]);
+ if (sercomm.tx.msg)
+ break;
+ }
+ if (sercomm.tx.msg) {
+ /* start of a new message, send start flag octet */
+ *ch = HDLC_FLAG;
+ sercomm.tx.next_char = sercomm.tx.msg->data;
+ sercomm_unlock(&flags);
+ return 1;
+ } else {
+ /* no more data avilable */
+ sercomm_unlock(&flags);
+ return 0;
+ }
+ }
+
+ if (sercomm.tx.state == RX_ST_ESCAPE) {
+ /* we've already transmitted the ESCAPE octet,
+ * we now need to transmit the escaped data */
+ *ch = *sercomm.tx.next_char++;
+ sercomm.tx.state = RX_ST_DATA;
+ } else if (sercomm.tx.next_char >= sercomm.tx.msg->tail) {
+ /* last character has already been transmitted,
+ * send end-of-message octet */
+ *ch = HDLC_FLAG;
+ /* we've reached the end of the message buffer */
+ msgb_free(sercomm.tx.msg);
+ sercomm.tx.msg = NULL;
+ sercomm.tx.next_char = NULL;
+ /* escaping for the two control octets */
+ } else if (*sercomm.tx.next_char == HDLC_FLAG ||
+ *sercomm.tx.next_char == HDLC_ESCAPE ||
+ *sercomm.tx.next_char == 0x00) {
+ /* send an escape octet */
+ *ch = HDLC_ESCAPE;
+ /* invert bit 5 of the next octet to be sent */
+ *sercomm.tx.next_char ^= (1 << 5);
+ sercomm.tx.state = RX_ST_ESCAPE;
+ } else {
+ /* standard case, simply send next octet */
+ *ch = *sercomm.tx.next_char++;
+ }
+
+ sercomm_unlock(&flags);
+ return 1;
+}
+
+/* register a handler for a given DLCI */
+int sercomm_register_rx_cb(uint8_t dlci, dlci_cb_t cb)
+{
+ if (dlci >= ARRAY_SIZE(sercomm.rx.dlci_handler))
+ return -EINVAL;
+
+ if (sercomm.rx.dlci_handler[dlci])
+ return -EBUSY;
+
+ sercomm.rx.dlci_handler[dlci] = cb;
+ return 0;
+}
+
+/* dispatch an incoming message once it is completely received */
+static void dispatch_rx_msg(uint8_t dlci, struct msgb *msg)
+{
+ if (dlci >= ARRAY_SIZE(sercomm.rx.dlci_handler) ||
+ !sercomm.rx.dlci_handler[dlci]) {
+ msgb_free(msg);
+ return;
+ }
+ sercomm.rx.dlci_handler[dlci](dlci, msg);
+}
+
+/* the driver has received one byte, pass it into sercomm layer */
+int sercomm_drv_rx_char(uint8_t ch)
+{
+ uint8_t *ptr;
+
+ /* we are always called from interrupt context in this function,
+ * which means that any data structures we use need to be for
+ * our exclusive access */
+ if (!sercomm.rx.msg)
+ sercomm.rx.msg = sercomm_alloc_msgb(SERCOMM_RX_MSG_SIZE);
+
+ if (msgb_tailroom(sercomm.rx.msg) == 0) {
+ //cons_puts("sercomm_drv_rx_char() overflow!\n");
+ msgb_free(sercomm.rx.msg);
+ sercomm.rx.msg = sercomm_alloc_msgb(SERCOMM_RX_MSG_SIZE);
+ sercomm.rx.state = RX_ST_WAIT_START;
+ return 0;
+ }
+
+ switch (sercomm.rx.state) {
+ case RX_ST_WAIT_START:
+ if (ch != HDLC_FLAG)
+ break;
+ sercomm.rx.state = RX_ST_ADDR;
+ break;
+ case RX_ST_ADDR:
+ sercomm.rx.dlci = ch;
+ sercomm.rx.state = RX_ST_CTRL;
+ break;
+ case RX_ST_CTRL:
+ sercomm.rx.ctrl = ch;
+ sercomm.rx.state = RX_ST_DATA;
+ break;
+ case RX_ST_DATA:
+ if (ch == HDLC_ESCAPE) {
+ /* drop the escape octet, but change state */
+ sercomm.rx.state = RX_ST_ESCAPE;
+ break;
+ } else if (ch == HDLC_FLAG) {
+ /* message is finished */
+ dispatch_rx_msg(sercomm.rx.dlci, sercomm.rx.msg);
+ /* allocate new buffer */
+ sercomm.rx.msg = NULL;
+ /* start all over again */
+ sercomm.rx.state = RX_ST_WAIT_START;
+
+ /* do not add the control char */
+ break;
+ }
+ /* default case: store the octet */
+ ptr = msgb_put(sercomm.rx.msg, 1);
+ *ptr = ch;
+ break;
+ case RX_ST_ESCAPE:
+ /* store bif-5-inverted octet in buffer */
+ ch ^= (1 << 5);
+ ptr = msgb_put(sercomm.rx.msg, 1);
+ *ptr = ch;
+ /* transition back to normal DATA state */
+ sercomm.rx.state = RX_ST_DATA;
+ break;
+ }
+
+ return 1;
+}
diff --git a/src/target/firmware/comm/sercomm_cons.c b/src/target/firmware/comm/sercomm_cons.c
new file mode 100644
index 00000000..a0dca405
--- /dev/null
+++ b/src/target/firmware/comm/sercomm_cons.c
@@ -0,0 +1,140 @@
+/* Serial console layer, layered on top of sercomm HDLC */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+
+#include <asm/system.h>
+
+#include <uart.h>
+
+#include <console.h>
+#include <osmocom/core/msgb.h>
+#include <comm/sercomm.h>
+#include <comm/sercomm_cons.h>
+
+static struct {
+ struct msgb *cur_msg;
+} scons;
+
+static void raw_puts(const char *s)
+{
+ int i = strlen(s);
+ while (i--)
+ uart_putchar_wait(SERCOMM_UART_NR, *s++);
+}
+
+#ifdef DEBUG
+#define raw_putd(x) raw_puts(x)
+#else
+#define raw_putd(x)
+#endif
+
+int sercomm_puts(const char *s)
+{
+ unsigned long flags;
+ const int len = strlen(s);
+ unsigned int bytes_left = len;
+
+ if (!sercomm_initialized()) {
+ raw_putd("sercomm not initialized: ");
+ raw_puts(s);
+ return len - 1;
+ }
+
+ /* This function is called from any context: Supervisor, IRQ, FIQ, ...
+ * as such, we need to ensure re-entrant calls are either supported or
+ * avoided. */
+ local_irq_save(flags);
+ local_fiq_disable();
+
+ while (bytes_left > 0) {
+ unsigned int write_num, space_left, flush;
+ uint8_t *data;
+
+ if (!scons.cur_msg)
+ scons.cur_msg = sercomm_alloc_msgb(SERCOMM_CONS_ALLOC);
+
+ if (!scons.cur_msg) {
+ raw_putd("cannot allocate sercomm msgb: ");
+ raw_puts(s);
+ return -ENOMEM;
+ }
+
+ /* space left in the current msgb */
+ space_left = msgb_tailroom(scons.cur_msg);
+
+ if (space_left <= bytes_left) {
+ write_num = space_left;
+ /* flush buffer when it is full */
+ flush = 1;
+ } else {
+ write_num = bytes_left;
+ flush = 0;
+ }
+
+ /* obtain pointer where to copy the data */
+ data = msgb_put(scons.cur_msg, write_num);
+
+ /* copy data while looking for \n line termination */
+ {
+ unsigned int i;
+ for (i = 0; i < write_num; i++) {
+ /* flush buffer at end of line, but skip
+ * flushing if we have a backlog in order to
+ * increase efficiency of msgb filling */
+ if (*s == '\n' &&
+ sercomm_tx_queue_depth(SC_DLCI_CONSOLE) < 4)
+ flush = 1;
+ *data++ = *s++;
+ }
+ }
+ bytes_left -= write_num;
+
+ if (flush) {
+ sercomm_sendmsg(SC_DLCI_CONSOLE, scons.cur_msg);
+ /* reset scons.cur_msg pointer to ensure we allocate
+ * a new one next round */
+ scons.cur_msg = NULL;
+ }
+ }
+
+ local_irq_restore(flags);
+
+ return len - 1;
+}
+
+int sercomm_putchar(int c)
+{
+ char s[2];
+ int rc;
+
+ s[0] = c & 0xff;
+ s[1] = '\0';
+
+ rc = sercomm_puts(s);
+ if (rc < 0)
+ return rc;
+
+ return c;
+}
diff --git a/src/target/firmware/comm/timer.c b/src/target/firmware/comm/timer.c
new file mode 100644
index 00000000..ce4f06d3
--- /dev/null
+++ b/src/target/firmware/comm/timer.c
@@ -0,0 +1,215 @@
+/* (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <debug.h>
+#include <osmocom/core/linuxlist.h>
+
+#include <comm/timer.h>
+
+#include <calypso/timer.h>
+#include <calypso/irq.h>
+
+#include <keypad.h>
+
+static LLIST_HEAD(timer_list);
+
+unsigned long volatile jiffies;
+
+#define time_after(a,b) \
+ (typecheck(unsigned long, a) && \
+ typecheck(unsigned long, b) && \
+ ((long)(b) - (long)(a) < 0))
+#define time_before(a,b) time_after(b,a)
+
+void osmo_timer_add(struct osmo_timer_list *timer)
+{
+ struct osmo_timer_list *list_timer;
+
+ /* TODO: Optimize and remember the closest item... */
+ timer->active = 1;
+
+ /* this might be called from within osmo_timers_update */
+ llist_for_each_entry(list_timer, &timer_list, entry)
+ if (timer == list_timer)
+ return;
+
+ timer->in_list = 1;
+ llist_add(&timer->entry, &timer_list);
+}
+
+void osmo_timer_schedule(struct osmo_timer_list *timer, int milliseconds)
+{
+ timer->expires = jiffies + ((milliseconds * HZ) / 1000);
+ osmo_timer_add(timer);
+}
+
+void osmo_timer_del(struct osmo_timer_list *timer)
+{
+ if (timer->in_list) {
+ timer->active = 0;
+ timer->in_list = 0;
+ llist_del(&timer->entry);
+ }
+}
+
+int osmo_timer_pending(struct osmo_timer_list *timer)
+{
+ return timer->active;
+}
+
+#if 0
+/*
+ * if we have a nearest time return the delta between the current
+ * time and the time of the nearest timer.
+ * If the nearest timer timed out return NULL and then we will
+ * dispatch everything after the select
+ */
+struct timeval *nearest_timer()
+{
+ struct timeval current_time;
+
+ if (s_nearest_time.tv_sec == 0 && s_nearest_time.tv_usec == 0)
+ return NULL;
+
+ if (gettimeofday(&current_time, NULL) == -1)
+ return NULL;
+
+ unsigned long long nearestTime = s_nearest_time.tv_sec * MICRO_SECONDS + s_nearest_time.tv_usec;
+ unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
+
+ if (nearestTime < currentTime) {
+ s_select_time.tv_sec = 0;
+ s_select_time.tv_usec = 0;
+ } else {
+ s_select_time.tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
+ s_select_time.tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
+ }
+
+ return &s_select_time;
+}
+
+/*
+ * Find the nearest time and update s_nearest_time
+ */
+void prepare_timers()
+{
+ struct osmo_timer_list *timer, *nearest_timer = NULL;
+ llist_for_each_entry(timer, &timer_list, entry) {
+ if (!nearest_timer || time_before(timer->expires, nearest_timer->expires)) {
+ nearest_timer = timer;
+ }
+ }
+
+ if (nearest_timer) {
+ s_nearest_time = nearest_timer->timeout;
+ } else {
+ memset(&s_nearest_time, 0, sizeof(struct timeval));
+ }
+}
+#endif
+
+/*
+ * fire all timers... and remove them
+ */
+int osmo_timers_update(void)
+{
+ struct osmo_timer_list *timer, *tmp;
+ int work = 0;
+
+ /*
+ * The callbacks might mess with our list and in this case
+ * even llist_for_each_entry_safe is not safe to use. To allow
+ * osmo_timer_del, osmo_timer_add, osmo_timer_schedule to be called from within
+ * the callback we jump through some loops.
+ *
+ * First we set the handled flag of each active timer to zero,
+ * then we iterate over the list and execute the callbacks. As the
+ * list might have been changed (specially the next) from within
+ * the callback we have to start over again. Once every callback
+ * is dispatched we will remove the non-active from the list.
+ *
+ * TODO: If this is a performance issue we can poison a global
+ * variable in osmo_timer_add and osmo_timer_del and only then restart.
+ */
+ llist_for_each_entry(timer, &timer_list, entry) {
+ timer->handled = 0;
+ }
+
+restart:
+ llist_for_each_entry(timer, &timer_list, entry) {
+ if (!timer->handled && time_before(timer->expires, jiffies)) {
+ timer->handled = 1;
+ timer->active = 0;
+ (*timer->cb)(timer->data);
+ work = 1;
+ goto restart;
+ }
+ }
+
+ llist_for_each_entry_safe(timer, tmp, &timer_list, entry) {
+ timer->handled = 0;
+ if (!timer->active) {
+ osmo_timer_del(timer);
+ }
+ }
+
+ return work;
+}
+
+int osmo_timers_check(void)
+{
+ struct osmo_timer_list *timer;
+ int i = 0;
+
+ llist_for_each_entry(timer, &timer_list, entry) {
+ i++;
+ }
+ return i;
+}
+
+static void timer_irq(enum irq_nr irq)
+{
+ /* we only increment jiffies here. FIXME: does this need to be atomic? */
+ jiffies++;
+
+ keypad_poll();
+}
+
+void timer_init(void)
+{
+ /* configure TIMER2 for our purpose */
+ hwtimer_enable(2, 1);
+ /* The timer runs at 13MHz / 32, i.e. 406.25kHz */
+#if (HZ == 100)
+ hwtimer_load(2, 4062);
+ hwtimer_config(2, 0, 1);
+#elif (HZ == 10)
+ /* prescaler 4, 1015 ticks until expiry */
+ hwtimer_load(2, 1015);
+ hwtimer_config(2, 4, 1);
+#endif
+ hwtimer_enable(2, 1);
+
+ /* register interrupt handler with default priority, EDGE triggered */
+ irq_register_handler(IRQ_TIMER2, &timer_irq);
+ irq_config(IRQ_TIMER2, 0, 1, -1);
+ irq_enable(IRQ_TIMER2);
+}
diff --git a/src/target/firmware/fb/4x6.c b/src/target/firmware/fb/4x6.c
new file mode 100644
index 00000000..2a35eba6
--- /dev/null
+++ b/src/target/firmware/fb/4x6.c
@@ -0,0 +1,731 @@
+#include <fb/font.h>
+static const uint8_t font_4x6_data[] = {
+/* --- new character space (32) starting at offset 0x0000 --- */
+ /*0000:*/ 4, 4, 1, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x00, /* ........ */
+/* --- new character exclam (33) starting at offset 0x0006 --- */
+ /*0006:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*000b:*/ 0x40, /* .#...... */
+ /*000c:*/ 0x40, /* .#...... */
+ /*000d:*/ 0x40, /* .#...... */
+ /*000e:*/ 0x00, /* ........ */
+ /*000f:*/ 0x40, /* .#...... */
+/* --- new character quotedbl (34) starting at offset 0x0010 --- */
+ /*0010:*/ 4, 4, 2, 0, 3, /* width and bbox (w,h,x,y) */
+ /*0015:*/ 0xa0, /* #.#..... */
+ /*0016:*/ 0xa0, /* #.#..... */
+/* --- new character numbersign (35) starting at offset 0x0017 --- */
+ /*0017:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*001c:*/ 0xa0, /* #.#..... */
+ /*001d:*/ 0xf0, /* ####.... */
+ /*001e:*/ 0xa0, /* #.#..... */
+ /*001f:*/ 0xf0, /* ####.... */
+ /*0020:*/ 0xa0, /* #.#..... */
+/* --- new character dollar (36) starting at offset 0x0021 --- */
+ /*0021:*/ 4, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0026:*/ 0x40, /* .#...... */
+ /*0027:*/ 0xe0, /* ###..... */
+ /*0028:*/ 0xc0, /* ##...... */
+ /*0029:*/ 0x20, /* ..#..... */
+ /*002a:*/ 0xe0, /* ###..... */
+ /*002b:*/ 0x40, /* .#...... */
+/* --- new character percent (37) starting at offset 0x002c --- */
+ /*002c:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0031:*/ 0x80, /* #....... */
+ /*0032:*/ 0x20, /* ..#..... */
+ /*0033:*/ 0x40, /* .#...... */
+ /*0034:*/ 0x80, /* #....... */
+ /*0035:*/ 0x20, /* ..#..... */
+/* --- new character ampersand (38) starting at offset 0x0036 --- */
+ /*0036:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*003b:*/ 0x40, /* .#...... */
+ /*003c:*/ 0xa0, /* #.#..... */
+ /*003d:*/ 0x40, /* .#...... */
+ /*003e:*/ 0xa0, /* #.#..... */
+ /*003f:*/ 0x50, /* .#.#.... */
+/* --- new character quotesingle (39) starting at offset 0x0040 --- */
+ /*0040:*/ 4, 4, 2, 0, 3, /* width and bbox (w,h,x,y) */
+ /*0045:*/ 0x40, /* .#...... */
+ /*0046:*/ 0x40, /* .#...... */
+/* --- new character parenleft (40) starting at offset 0x0047 --- */
+ /*0047:*/ 4, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*004c:*/ 0x20, /* ..#..... */
+ /*004d:*/ 0x40, /* .#...... */
+ /*004e:*/ 0x40, /* .#...... */
+ /*004f:*/ 0x40, /* .#...... */
+ /*0050:*/ 0x40, /* .#...... */
+ /*0051:*/ 0x20, /* ..#..... */
+/* --- new character parenright (41) starting at offset 0x0052 --- */
+ /*0052:*/ 4, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0057:*/ 0x80, /* #....... */
+ /*0058:*/ 0x40, /* .#...... */
+ /*0059:*/ 0x40, /* .#...... */
+ /*005a:*/ 0x40, /* .#...... */
+ /*005b:*/ 0x40, /* .#...... */
+ /*005c:*/ 0x80, /* #....... */
+/* --- new character asterisk (42) starting at offset 0x005d --- */
+ /*005d:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0062:*/ 0xa0, /* #.#..... */
+ /*0063:*/ 0x40, /* .#...... */
+ /*0064:*/ 0xe0, /* ###..... */
+ /*0065:*/ 0x40, /* .#...... */
+ /*0066:*/ 0xa0, /* #.#..... */
+/* --- new character plus (43) starting at offset 0x0067 --- */
+ /*0067:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*006c:*/ 0x40, /* .#...... */
+ /*006d:*/ 0x40, /* .#...... */
+ /*006e:*/ 0xe0, /* ###..... */
+ /*006f:*/ 0x40, /* .#...... */
+ /*0070:*/ 0x40, /* .#...... */
+/* --- new character comma (44) starting at offset 0x0071 --- */
+ /*0071:*/ 4, 4, 2, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0076:*/ 0x40, /* .#...... */
+ /*0077:*/ 0x80, /* #....... */
+/* --- new character hyphen (45) starting at offset 0x0078 --- */
+ /*0078:*/ 4, 4, 1, 0, 2, /* width and bbox (w,h,x,y) */
+ /*007d:*/ 0xe0, /* ###..... */
+/* --- new character period (46) starting at offset 0x007e --- */
+ /*007e:*/ 4, 4, 1, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0083:*/ 0x40, /* .#...... */
+/* --- new character slash (47) starting at offset 0x0084 --- */
+ /*0084:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0089:*/ 0x20, /* ..#..... */
+ /*008a:*/ 0x20, /* ..#..... */
+ /*008b:*/ 0x40, /* .#...... */
+ /*008c:*/ 0x80, /* #....... */
+ /*008d:*/ 0x80, /* #....... */
+/* --- new character zero (48) starting at offset 0x008e --- */
+ /*008e:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0093:*/ 0x40, /* .#...... */
+ /*0094:*/ 0xa0, /* #.#..... */
+ /*0095:*/ 0xe0, /* ###..... */
+ /*0096:*/ 0xa0, /* #.#..... */
+ /*0097:*/ 0x40, /* .#...... */
+/* --- new character one (49) starting at offset 0x0098 --- */
+ /*0098:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*009d:*/ 0x40, /* .#...... */
+ /*009e:*/ 0xc0, /* ##...... */
+ /*009f:*/ 0x40, /* .#...... */
+ /*00a0:*/ 0x40, /* .#...... */
+ /*00a1:*/ 0xe0, /* ###..... */
+/* --- new character two (50) starting at offset 0x00a2 --- */
+ /*00a2:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00a7:*/ 0x40, /* .#...... */
+ /*00a8:*/ 0xa0, /* #.#..... */
+ /*00a9:*/ 0x20, /* ..#..... */
+ /*00aa:*/ 0x40, /* .#...... */
+ /*00ab:*/ 0xe0, /* ###..... */
+/* --- new character three (51) starting at offset 0x00ac --- */
+ /*00ac:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00b1:*/ 0xe0, /* ###..... */
+ /*00b2:*/ 0x20, /* ..#..... */
+ /*00b3:*/ 0x40, /* .#...... */
+ /*00b4:*/ 0x20, /* ..#..... */
+ /*00b5:*/ 0xc0, /* ##...... */
+/* --- new character four (52) starting at offset 0x00b6 --- */
+ /*00b6:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00bb:*/ 0xa0, /* #.#..... */
+ /*00bc:*/ 0xa0, /* #.#..... */
+ /*00bd:*/ 0xe0, /* ###..... */
+ /*00be:*/ 0x20, /* ..#..... */
+ /*00bf:*/ 0x20, /* ..#..... */
+/* --- new character five (53) starting at offset 0x00c0 --- */
+ /*00c0:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00c5:*/ 0xe0, /* ###..... */
+ /*00c6:*/ 0x80, /* #....... */
+ /*00c7:*/ 0xc0, /* ##...... */
+ /*00c8:*/ 0x20, /* ..#..... */
+ /*00c9:*/ 0xc0, /* ##...... */
+/* --- new character six (54) starting at offset 0x00ca --- */
+ /*00ca:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00cf:*/ 0x60, /* .##..... */
+ /*00d0:*/ 0x80, /* #....... */
+ /*00d1:*/ 0xc0, /* ##...... */
+ /*00d2:*/ 0xa0, /* #.#..... */
+ /*00d3:*/ 0x40, /* .#...... */
+/* --- new character seven (55) starting at offset 0x00d4 --- */
+ /*00d4:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00d9:*/ 0xe0, /* ###..... */
+ /*00da:*/ 0x20, /* ..#..... */
+ /*00db:*/ 0x40, /* .#...... */
+ /*00dc:*/ 0x80, /* #....... */
+ /*00dd:*/ 0x80, /* #....... */
+/* --- new character eight (56) starting at offset 0x00de --- */
+ /*00de:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00e3:*/ 0x60, /* .##..... */
+ /*00e4:*/ 0xa0, /* #.#..... */
+ /*00e5:*/ 0x40, /* .#...... */
+ /*00e6:*/ 0xa0, /* #.#..... */
+ /*00e7:*/ 0xc0, /* ##...... */
+/* --- new character nine (57) starting at offset 0x00e8 --- */
+ /*00e8:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00ed:*/ 0x40, /* .#...... */
+ /*00ee:*/ 0xa0, /* #.#..... */
+ /*00ef:*/ 0x60, /* .##..... */
+ /*00f0:*/ 0x20, /* ..#..... */
+ /*00f1:*/ 0xc0, /* ##...... */
+/* --- new character colon (58) starting at offset 0x00f2 --- */
+ /*00f2:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00f7:*/ 0x40, /* .#...... */
+ /*00f8:*/ 0x00, /* ........ */
+ /*00f9:*/ 0x00, /* ........ */
+ /*00fa:*/ 0x40, /* .#...... */
+/* --- new character semicolon (59) starting at offset 0x00fb --- */
+ /*00fb:*/ 4, 4, 5, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0100:*/ 0x40, /* .#...... */
+ /*0101:*/ 0x00, /* ........ */
+ /*0102:*/ 0x00, /* ........ */
+ /*0103:*/ 0x40, /* .#...... */
+ /*0104:*/ 0x80, /* #....... */
+/* --- new character less (60) starting at offset 0x0105 --- */
+ /*0105:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*010a:*/ 0x20, /* ..#..... */
+ /*010b:*/ 0x40, /* .#...... */
+ /*010c:*/ 0x80, /* #....... */
+ /*010d:*/ 0x40, /* .#...... */
+ /*010e:*/ 0x20, /* ..#..... */
+/* --- new character equal (61) starting at offset 0x010f --- */
+ /*010f:*/ 4, 4, 3, 0, 1, /* width and bbox (w,h,x,y) */
+ /*0114:*/ 0xe0, /* ###..... */
+ /*0115:*/ 0x00, /* ........ */
+ /*0116:*/ 0xe0, /* ###..... */
+/* --- new character greater (62) starting at offset 0x0117 --- */
+ /*0117:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*011c:*/ 0x80, /* #....... */
+ /*011d:*/ 0x40, /* .#...... */
+ /*011e:*/ 0x20, /* ..#..... */
+ /*011f:*/ 0x40, /* .#...... */
+ /*0120:*/ 0x80, /* #....... */
+/* --- new character question (63) starting at offset 0x0121 --- */
+ /*0121:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0126:*/ 0xc0, /* ##...... */
+ /*0127:*/ 0x20, /* ..#..... */
+ /*0128:*/ 0x40, /* .#...... */
+ /*0129:*/ 0x00, /* ........ */
+ /*012a:*/ 0x40, /* .#...... */
+/* --- new character at (64) starting at offset 0x012b --- */
+ /*012b:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0130:*/ 0x60, /* .##..... */
+ /*0131:*/ 0xa0, /* #.#..... */
+ /*0132:*/ 0xa0, /* #.#..... */
+ /*0133:*/ 0x80, /* #....... */
+ /*0134:*/ 0x60, /* .##..... */
+/* --- new character A (65) starting at offset 0x0135 --- */
+ /*0135:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*013a:*/ 0x40, /* .#...... */
+ /*013b:*/ 0xa0, /* #.#..... */
+ /*013c:*/ 0xe0, /* ###..... */
+ /*013d:*/ 0xa0, /* #.#..... */
+ /*013e:*/ 0xa0, /* #.#..... */
+/* --- new character B (66) starting at offset 0x013f --- */
+ /*013f:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0144:*/ 0xc0, /* ##...... */
+ /*0145:*/ 0xa0, /* #.#..... */
+ /*0146:*/ 0xc0, /* ##...... */
+ /*0147:*/ 0xa0, /* #.#..... */
+ /*0148:*/ 0xc0, /* ##...... */
+/* --- new character C (67) starting at offset 0x0149 --- */
+ /*0149:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*014e:*/ 0x40, /* .#...... */
+ /*014f:*/ 0xa0, /* #.#..... */
+ /*0150:*/ 0x80, /* #....... */
+ /*0151:*/ 0xa0, /* #.#..... */
+ /*0152:*/ 0x40, /* .#...... */
+/* --- new character D (68) starting at offset 0x0153 --- */
+ /*0153:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0158:*/ 0xc0, /* ##...... */
+ /*0159:*/ 0xa0, /* #.#..... */
+ /*015a:*/ 0xa0, /* #.#..... */
+ /*015b:*/ 0xa0, /* #.#..... */
+ /*015c:*/ 0xc0, /* ##...... */
+/* --- new character E (69) starting at offset 0x015d --- */
+ /*015d:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0162:*/ 0xe0, /* ###..... */
+ /*0163:*/ 0x80, /* #....... */
+ /*0164:*/ 0xc0, /* ##...... */
+ /*0165:*/ 0x80, /* #....... */
+ /*0166:*/ 0xe0, /* ###..... */
+/* --- new character F (70) starting at offset 0x0167 --- */
+ /*0167:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*016c:*/ 0xe0, /* ###..... */
+ /*016d:*/ 0x80, /* #....... */
+ /*016e:*/ 0xc0, /* ##...... */
+ /*016f:*/ 0x80, /* #....... */
+ /*0170:*/ 0x80, /* #....... */
+/* --- new character G (71) starting at offset 0x0171 --- */
+ /*0171:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0176:*/ 0x60, /* .##..... */
+ /*0177:*/ 0x80, /* #....... */
+ /*0178:*/ 0xa0, /* #.#..... */
+ /*0179:*/ 0xa0, /* #.#..... */
+ /*017a:*/ 0x60, /* .##..... */
+/* --- new character H (72) starting at offset 0x017b --- */
+ /*017b:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0180:*/ 0xa0, /* #.#..... */
+ /*0181:*/ 0xa0, /* #.#..... */
+ /*0182:*/ 0xe0, /* ###..... */
+ /*0183:*/ 0xa0, /* #.#..... */
+ /*0184:*/ 0xa0, /* #.#..... */
+/* --- new character I (73) starting at offset 0x0185 --- */
+ /*0185:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*018a:*/ 0xe0, /* ###..... */
+ /*018b:*/ 0x40, /* .#...... */
+ /*018c:*/ 0x40, /* .#...... */
+ /*018d:*/ 0x40, /* .#...... */
+ /*018e:*/ 0xe0, /* ###..... */
+/* --- new character J (74) starting at offset 0x018f --- */
+ /*018f:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0194:*/ 0x20, /* ..#..... */
+ /*0195:*/ 0x20, /* ..#..... */
+ /*0196:*/ 0x20, /* ..#..... */
+ /*0197:*/ 0xa0, /* #.#..... */
+ /*0198:*/ 0x40, /* .#...... */
+/* --- new character K (75) starting at offset 0x0199 --- */
+ /*0199:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*019e:*/ 0xa0, /* #.#..... */
+ /*019f:*/ 0xa0, /* #.#..... */
+ /*01a0:*/ 0xc0, /* ##...... */
+ /*01a1:*/ 0xa0, /* #.#..... */
+ /*01a2:*/ 0xa0, /* #.#..... */
+/* --- new character L (76) starting at offset 0x01a3 --- */
+ /*01a3:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01a8:*/ 0x80, /* #....... */
+ /*01a9:*/ 0x80, /* #....... */
+ /*01aa:*/ 0x80, /* #....... */
+ /*01ab:*/ 0x80, /* #....... */
+ /*01ac:*/ 0xe0, /* ###..... */
+/* --- new character M (77) starting at offset 0x01ad --- */
+ /*01ad:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01b2:*/ 0xa0, /* #.#..... */
+ /*01b3:*/ 0xe0, /* ###..... */
+ /*01b4:*/ 0xe0, /* ###..... */
+ /*01b5:*/ 0xa0, /* #.#..... */
+ /*01b6:*/ 0xa0, /* #.#..... */
+/* --- new character N (78) starting at offset 0x01b7 --- */
+ /*01b7:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01bc:*/ 0x20, /* ..#..... */
+ /*01bd:*/ 0xa0, /* #.#..... */
+ /*01be:*/ 0xe0, /* ###..... */
+ /*01bf:*/ 0xa0, /* #.#..... */
+ /*01c0:*/ 0x80, /* #....... */
+/* --- new character O (79) starting at offset 0x01c1 --- */
+ /*01c1:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01c6:*/ 0x40, /* .#...... */
+ /*01c7:*/ 0xa0, /* #.#..... */
+ /*01c8:*/ 0xa0, /* #.#..... */
+ /*01c9:*/ 0xa0, /* #.#..... */
+ /*01ca:*/ 0x40, /* .#...... */
+/* --- new character P (80) starting at offset 0x01cb --- */
+ /*01cb:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01d0:*/ 0xc0, /* ##...... */
+ /*01d1:*/ 0xa0, /* #.#..... */
+ /*01d2:*/ 0xc0, /* ##...... */
+ /*01d3:*/ 0x80, /* #....... */
+ /*01d4:*/ 0x80, /* #....... */
+/* --- new character Q (81) starting at offset 0x01d5 --- */
+ /*01d5:*/ 4, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*01da:*/ 0x40, /* .#...... */
+ /*01db:*/ 0xa0, /* #.#..... */
+ /*01dc:*/ 0xa0, /* #.#..... */
+ /*01dd:*/ 0xa0, /* #.#..... */
+ /*01de:*/ 0x40, /* .#...... */
+ /*01df:*/ 0x20, /* ..#..... */
+/* --- new character R (82) starting at offset 0x01e0 --- */
+ /*01e0:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01e5:*/ 0xc0, /* ##...... */
+ /*01e6:*/ 0xa0, /* #.#..... */
+ /*01e7:*/ 0xc0, /* ##...... */
+ /*01e8:*/ 0xa0, /* #.#..... */
+ /*01e9:*/ 0xa0, /* #.#..... */
+/* --- new character S (83) starting at offset 0x01ea --- */
+ /*01ea:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01ef:*/ 0x60, /* .##..... */
+ /*01f0:*/ 0x80, /* #....... */
+ /*01f1:*/ 0x40, /* .#...... */
+ /*01f2:*/ 0x20, /* ..#..... */
+ /*01f3:*/ 0xc0, /* ##...... */
+/* --- new character T (84) starting at offset 0x01f4 --- */
+ /*01f4:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01f9:*/ 0xe0, /* ###..... */
+ /*01fa:*/ 0x40, /* .#...... */
+ /*01fb:*/ 0x40, /* .#...... */
+ /*01fc:*/ 0x40, /* .#...... */
+ /*01fd:*/ 0x40, /* .#...... */
+/* --- new character U (85) starting at offset 0x01fe --- */
+ /*01fe:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0203:*/ 0xa0, /* #.#..... */
+ /*0204:*/ 0xa0, /* #.#..... */
+ /*0205:*/ 0xa0, /* #.#..... */
+ /*0206:*/ 0xa0, /* #.#..... */
+ /*0207:*/ 0xe0, /* ###..... */
+/* --- new character V (86) starting at offset 0x0208 --- */
+ /*0208:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*020d:*/ 0xa0, /* #.#..... */
+ /*020e:*/ 0xa0, /* #.#..... */
+ /*020f:*/ 0xa0, /* #.#..... */
+ /*0210:*/ 0xe0, /* ###..... */
+ /*0211:*/ 0x40, /* .#...... */
+/* --- new character W (87) starting at offset 0x0212 --- */
+ /*0212:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0217:*/ 0xa0, /* #.#..... */
+ /*0218:*/ 0xa0, /* #.#..... */
+ /*0219:*/ 0xe0, /* ###..... */
+ /*021a:*/ 0xe0, /* ###..... */
+ /*021b:*/ 0xa0, /* #.#..... */
+/* --- new character X (88) starting at offset 0x021c --- */
+ /*021c:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0221:*/ 0xa0, /* #.#..... */
+ /*0222:*/ 0xa0, /* #.#..... */
+ /*0223:*/ 0x40, /* .#...... */
+ /*0224:*/ 0xa0, /* #.#..... */
+ /*0225:*/ 0xa0, /* #.#..... */
+/* --- new character Y (89) starting at offset 0x0226 --- */
+ /*0226:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*022b:*/ 0xa0, /* #.#..... */
+ /*022c:*/ 0xa0, /* #.#..... */
+ /*022d:*/ 0x40, /* .#...... */
+ /*022e:*/ 0x40, /* .#...... */
+ /*022f:*/ 0x40, /* .#...... */
+/* --- new character Z (90) starting at offset 0x0230 --- */
+ /*0230:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0235:*/ 0xe0, /* ###..... */
+ /*0236:*/ 0x20, /* ..#..... */
+ /*0237:*/ 0x40, /* .#...... */
+ /*0238:*/ 0x80, /* #....... */
+ /*0239:*/ 0xe0, /* ###..... */
+/* --- new character bracketleft (91) starting at offset 0x023a --- */
+ /*023a:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*023f:*/ 0x60, /* .##..... */
+ /*0240:*/ 0x40, /* .#...... */
+ /*0241:*/ 0x40, /* .#...... */
+ /*0242:*/ 0x40, /* .#...... */
+ /*0243:*/ 0x60, /* .##..... */
+/* --- new character backslash (92) starting at offset 0x0244 --- */
+ /*0244:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0249:*/ 0x80, /* #....... */
+ /*024a:*/ 0x80, /* #....... */
+ /*024b:*/ 0x40, /* .#...... */
+ /*024c:*/ 0x20, /* ..#..... */
+ /*024d:*/ 0x20, /* ..#..... */
+/* --- new character bracketright (93) starting at offset 0x024e --- */
+ /*024e:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0253:*/ 0xc0, /* ##...... */
+ /*0254:*/ 0x40, /* .#...... */
+ /*0255:*/ 0x40, /* .#...... */
+ /*0256:*/ 0x40, /* .#...... */
+ /*0257:*/ 0xc0, /* ##...... */
+/* --- new character asciicircum (94) starting at offset 0x0258 --- */
+ /*0258:*/ 4, 4, 2, 0, 3, /* width and bbox (w,h,x,y) */
+ /*025d:*/ 0x40, /* .#...... */
+ /*025e:*/ 0xa0, /* #.#..... */
+/* --- new character underscore (95) starting at offset 0x025f --- */
+ /*025f:*/ 4, 4, 1, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0264:*/ 0xe0, /* ###..... */
+/* --- new character grave (96) starting at offset 0x0265 --- */
+ /*0265:*/ 4, 4, 2, 0, 3, /* width and bbox (w,h,x,y) */
+ /*026a:*/ 0x40, /* .#...... */
+ /*026b:*/ 0x20, /* ..#..... */
+/* --- new character a (97) starting at offset 0x026c --- */
+ /*026c:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0271:*/ 0x60, /* .##..... */
+ /*0272:*/ 0xa0, /* #.#..... */
+ /*0273:*/ 0xa0, /* #.#..... */
+ /*0274:*/ 0x60, /* .##..... */
+/* --- new character b (98) starting at offset 0x0275 --- */
+ /*0275:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*027a:*/ 0x80, /* #....... */
+ /*027b:*/ 0xc0, /* ##...... */
+ /*027c:*/ 0xa0, /* #.#..... */
+ /*027d:*/ 0xa0, /* #.#..... */
+ /*027e:*/ 0xc0, /* ##...... */
+/* --- new character c (99) starting at offset 0x027f --- */
+ /*027f:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0284:*/ 0x60, /* .##..... */
+ /*0285:*/ 0x80, /* #....... */
+ /*0286:*/ 0x80, /* #....... */
+ /*0287:*/ 0x60, /* .##..... */
+/* --- new character d (100) starting at offset 0x0288 --- */
+ /*0288:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*028d:*/ 0x20, /* ..#..... */
+ /*028e:*/ 0x60, /* .##..... */
+ /*028f:*/ 0xa0, /* #.#..... */
+ /*0290:*/ 0xa0, /* #.#..... */
+ /*0291:*/ 0x60, /* .##..... */
+/* --- new character e (101) starting at offset 0x0292 --- */
+ /*0292:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0297:*/ 0x40, /* .#...... */
+ /*0298:*/ 0xa0, /* #.#..... */
+ /*0299:*/ 0xc0, /* ##...... */
+ /*029a:*/ 0x60, /* .##..... */
+/* --- new character f (102) starting at offset 0x029b --- */
+ /*029b:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02a0:*/ 0x20, /* ..#..... */
+ /*02a1:*/ 0x40, /* .#...... */
+ /*02a2:*/ 0xe0, /* ###..... */
+ /*02a3:*/ 0x40, /* .#...... */
+ /*02a4:*/ 0x40, /* .#...... */
+/* --- new character g (103) starting at offset 0x02a5 --- */
+ /*02a5:*/ 4, 4, 5, 0, -1, /* width and bbox (w,h,x,y) */
+ /*02aa:*/ 0x60, /* .##..... */
+ /*02ab:*/ 0xa0, /* #.#..... */
+ /*02ac:*/ 0x60, /* .##..... */
+ /*02ad:*/ 0x20, /* ..#..... */
+ /*02ae:*/ 0xc0, /* ##...... */
+/* --- new character h (104) starting at offset 0x02af --- */
+ /*02af:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02b4:*/ 0x80, /* #....... */
+ /*02b5:*/ 0xc0, /* ##...... */
+ /*02b6:*/ 0xa0, /* #.#..... */
+ /*02b7:*/ 0xa0, /* #.#..... */
+ /*02b8:*/ 0xa0, /* #.#..... */
+/* --- new character i (105) starting at offset 0x02b9 --- */
+ /*02b9:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02be:*/ 0x40, /* .#...... */
+ /*02bf:*/ 0x00, /* ........ */
+ /*02c0:*/ 0xc0, /* ##...... */
+ /*02c1:*/ 0x40, /* .#...... */
+ /*02c2:*/ 0xe0, /* ###..... */
+/* --- new character j (106) starting at offset 0x02c3 --- */
+ /*02c3:*/ 4, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*02c8:*/ 0x20, /* ..#..... */
+ /*02c9:*/ 0x00, /* ........ */
+ /*02ca:*/ 0x20, /* ..#..... */
+ /*02cb:*/ 0x20, /* ..#..... */
+ /*02cc:*/ 0x20, /* ..#..... */
+ /*02cd:*/ 0xc0, /* ##...... */
+/* --- new character k (107) starting at offset 0x02ce --- */
+ /*02ce:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02d3:*/ 0x80, /* #....... */
+ /*02d4:*/ 0xa0, /* #.#..... */
+ /*02d5:*/ 0xc0, /* ##...... */
+ /*02d6:*/ 0xa0, /* #.#..... */
+ /*02d7:*/ 0xa0, /* #.#..... */
+/* --- new character l (108) starting at offset 0x02d8 --- */
+ /*02d8:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02dd:*/ 0xc0, /* ##...... */
+ /*02de:*/ 0x40, /* .#...... */
+ /*02df:*/ 0x40, /* .#...... */
+ /*02e0:*/ 0x40, /* .#...... */
+ /*02e1:*/ 0xe0, /* ###..... */
+/* --- new character m (109) starting at offset 0x02e2 --- */
+ /*02e2:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02e7:*/ 0xa0, /* #.#..... */
+ /*02e8:*/ 0xe0, /* ###..... */
+ /*02e9:*/ 0xa0, /* #.#..... */
+ /*02ea:*/ 0xa0, /* #.#..... */
+/* --- new character n (110) starting at offset 0x02eb --- */
+ /*02eb:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02f0:*/ 0xc0, /* ##...... */
+ /*02f1:*/ 0xa0, /* #.#..... */
+ /*02f2:*/ 0xa0, /* #.#..... */
+ /*02f3:*/ 0xa0, /* #.#..... */
+/* --- new character o (111) starting at offset 0x02f4 --- */
+ /*02f4:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02f9:*/ 0x40, /* .#...... */
+ /*02fa:*/ 0xa0, /* #.#..... */
+ /*02fb:*/ 0xa0, /* #.#..... */
+ /*02fc:*/ 0x40, /* .#...... */
+/* --- new character p (112) starting at offset 0x02fd --- */
+ /*02fd:*/ 4, 4, 5, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0302:*/ 0xc0, /* ##...... */
+ /*0303:*/ 0xa0, /* #.#..... */
+ /*0304:*/ 0xc0, /* ##...... */
+ /*0305:*/ 0x80, /* #....... */
+ /*0306:*/ 0x80, /* #....... */
+/* --- new character q (113) starting at offset 0x0307 --- */
+ /*0307:*/ 4, 4, 5, 0, -1, /* width and bbox (w,h,x,y) */
+ /*030c:*/ 0x60, /* .##..... */
+ /*030d:*/ 0xa0, /* #.#..... */
+ /*030e:*/ 0xa0, /* #.#..... */
+ /*030f:*/ 0x60, /* .##..... */
+ /*0310:*/ 0x20, /* ..#..... */
+/* --- new character r (114) starting at offset 0x0311 --- */
+ /*0311:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0316:*/ 0xa0, /* #.#..... */
+ /*0317:*/ 0xc0, /* ##...... */
+ /*0318:*/ 0x80, /* #....... */
+ /*0319:*/ 0x80, /* #....... */
+/* --- new character s (115) starting at offset 0x031a --- */
+ /*031a:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*031f:*/ 0x60, /* .##..... */
+ /*0320:*/ 0xc0, /* ##...... */
+ /*0321:*/ 0x20, /* ..#..... */
+ /*0322:*/ 0xc0, /* ##...... */
+/* --- new character t (116) starting at offset 0x0323 --- */
+ /*0323:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0328:*/ 0x40, /* .#...... */
+ /*0329:*/ 0xe0, /* ###..... */
+ /*032a:*/ 0x40, /* .#...... */
+ /*032b:*/ 0x40, /* .#...... */
+ /*032c:*/ 0x20, /* ..#..... */
+/* --- new character u (117) starting at offset 0x032d --- */
+ /*032d:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0332:*/ 0xa0, /* #.#..... */
+ /*0333:*/ 0xa0, /* #.#..... */
+ /*0334:*/ 0xa0, /* #.#..... */
+ /*0335:*/ 0x60, /* .##..... */
+/* --- new character v (118) starting at offset 0x0336 --- */
+ /*0336:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*033b:*/ 0xa0, /* #.#..... */
+ /*033c:*/ 0xa0, /* #.#..... */
+ /*033d:*/ 0xa0, /* #.#..... */
+ /*033e:*/ 0x40, /* .#...... */
+/* --- new character w (119) starting at offset 0x033f --- */
+ /*033f:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0344:*/ 0xa0, /* #.#..... */
+ /*0345:*/ 0xa0, /* #.#..... */
+ /*0346:*/ 0xe0, /* ###..... */
+ /*0347:*/ 0xa0, /* #.#..... */
+/* --- new character x (120) starting at offset 0x0348 --- */
+ /*0348:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*034d:*/ 0xa0, /* #.#..... */
+ /*034e:*/ 0x40, /* .#...... */
+ /*034f:*/ 0x40, /* .#...... */
+ /*0350:*/ 0xa0, /* #.#..... */
+/* --- new character y (121) starting at offset 0x0351 --- */
+ /*0351:*/ 4, 4, 5, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0356:*/ 0xa0, /* #.#..... */
+ /*0357:*/ 0xa0, /* #.#..... */
+ /*0358:*/ 0x60, /* .##..... */
+ /*0359:*/ 0x20, /* ..#..... */
+ /*035a:*/ 0xc0, /* ##...... */
+/* --- new character z (122) starting at offset 0x035b --- */
+ /*035b:*/ 4, 4, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0360:*/ 0xe0, /* ###..... */
+ /*0361:*/ 0x20, /* ..#..... */
+ /*0362:*/ 0x40, /* .#...... */
+ /*0363:*/ 0xe0, /* ###..... */
+/* --- new character braceleft (123) starting at offset 0x0364 --- */
+ /*0364:*/ 4, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0369:*/ 0x20, /* ..#..... */
+ /*036a:*/ 0x40, /* .#...... */
+ /*036b:*/ 0xc0, /* ##...... */
+ /*036c:*/ 0x40, /* .#...... */
+ /*036d:*/ 0x40, /* .#...... */
+ /*036e:*/ 0x20, /* ..#..... */
+/* --- new character bar (124) starting at offset 0x036f --- */
+ /*036f:*/ 4, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0374:*/ 0x40, /* .#...... */
+ /*0375:*/ 0x40, /* .#...... */
+ /*0376:*/ 0x40, /* .#...... */
+ /*0377:*/ 0x40, /* .#...... */
+ /*0378:*/ 0x40, /* .#...... */
+/* --- new character braceright (125) starting at offset 0x0379 --- */
+ /*0379:*/ 4, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*037e:*/ 0x80, /* #....... */
+ /*037f:*/ 0x40, /* .#...... */
+ /*0380:*/ 0x60, /* .##..... */
+ /*0381:*/ 0x40, /* .#...... */
+ /*0382:*/ 0x40, /* .#...... */
+ /*0383:*/ 0x80, /* #....... */
+/* --- new character asciitilde (126) starting at offset 0x0384 --- */
+ /*0384:*/ 4, 4, 2, 0, 3, /* width and bbox (w,h,x,y) */
+ /*0389:*/ 0x50, /* .#.#.... */
+ /*038a:*/ 0xa0, /* #.#..... */
+};
+static const uint16_t font_4x6_offsets[] = {
+0x0000 /* space */,
+ 0x0006 /* exclam */,
+ 0x0010 /* quotedbl */,
+ 0x0017 /* numbersign */,
+ 0x0021 /* dollar */,
+ 0x002c /* percent */,
+ 0x0036 /* ampersand */,
+ 0x0040 /* quotesingle */,
+ 0x0047 /* parenleft */,
+ 0x0052 /* parenright */,
+ 0x005d /* asterisk */,
+ 0x0067 /* plus */,
+ 0x0071 /* comma */,
+ 0x0078 /* hyphen */,
+ 0x007e /* period */,
+ 0x0084 /* slash */,
+ 0x008e /* zero */,
+ 0x0098 /* one */,
+ 0x00a2 /* two */,
+ 0x00ac /* three */,
+ 0x00b6 /* four */,
+ 0x00c0 /* five */,
+ 0x00ca /* six */,
+ 0x00d4 /* seven */,
+ 0x00de /* eight */,
+ 0x00e8 /* nine */,
+ 0x00f2 /* colon */,
+ 0x00fb /* semicolon */,
+ 0x0105 /* less */,
+ 0x010f /* equal */,
+ 0x0117 /* greater */,
+ 0x0121 /* question */,
+ 0x012b /* at */,
+ 0x0135 /* A */,
+ 0x013f /* B */,
+ 0x0149 /* C */,
+ 0x0153 /* D */,
+ 0x015d /* E */,
+ 0x0167 /* F */,
+ 0x0171 /* G */,
+ 0x017b /* H */,
+ 0x0185 /* I */,
+ 0x018f /* J */,
+ 0x0199 /* K */,
+ 0x01a3 /* L */,
+ 0x01ad /* M */,
+ 0x01b7 /* N */,
+ 0x01c1 /* O */,
+ 0x01cb /* P */,
+ 0x01d5 /* Q */,
+ 0x01e0 /* R */,
+ 0x01ea /* S */,
+ 0x01f4 /* T */,
+ 0x01fe /* U */,
+ 0x0208 /* V */,
+ 0x0212 /* W */,
+ 0x021c /* X */,
+ 0x0226 /* Y */,
+ 0x0230 /* Z */,
+ 0x023a /* bracketleft */,
+ 0x0244 /* backslash */,
+ 0x024e /* bracketright */,
+ 0x0258 /* asciicircum */,
+ 0x025f /* underscore */,
+ 0x0265 /* grave */,
+ 0x026c /* a */,
+ 0x0275 /* b */,
+ 0x027f /* c */,
+ 0x0288 /* d */,
+ 0x0292 /* e */,
+ 0x029b /* f */,
+ 0x02a5 /* g */,
+ 0x02af /* h */,
+ 0x02b9 /* i */,
+ 0x02c3 /* j */,
+ 0x02ce /* k */,
+ 0x02d8 /* l */,
+ 0x02e2 /* m */,
+ 0x02eb /* n */,
+ 0x02f4 /* o */,
+ 0x02fd /* p */,
+ 0x0307 /* q */,
+ 0x0311 /* r */,
+ 0x031a /* s */,
+ 0x0323 /* t */,
+ 0x032d /* u */,
+ 0x0336 /* v */,
+ 0x033f /* w */,
+ 0x0348 /* x */,
+ 0x0351 /* y */,
+ 0x035b /* z */,
+ 0x0364 /* braceleft */,
+ 0x036f /* bar */,
+ 0x0379 /* braceright */,
+ 0x0384 /* asciitilde */,
+ 0xffff /* (no glyph) */
+};
+const struct fb_font font_4x6 = {
+ .height = 6,
+ .ascent = 5,
+ .firstchar = 32, /* space */
+ .lastchar = 127, /* ? */
+ .chardata = font_4x6_data,
+ .charoffs = font_4x6_offsets,
+};
diff --git a/src/target/firmware/fb/5x8.c b/src/target/firmware/fb/5x8.c
new file mode 100644
index 00000000..e2003298
--- /dev/null
+++ b/src/target/firmware/fb/5x8.c
@@ -0,0 +1,802 @@
+#include <fb/font.h>
+static const uint8_t font_5x8_data[] = {
+/* --- new character space (32) starting at offset 0x0000 --- */
+ /*0000:*/ 5, 5, 1, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x00, /* ........ */
+/* --- new character exclam (33) starting at offset 0x0006 --- */
+ /*0006:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*000b:*/ 0x20, /* ..#..... */
+ /*000c:*/ 0x20, /* ..#..... */
+ /*000d:*/ 0x20, /* ..#..... */
+ /*000e:*/ 0x20, /* ..#..... */
+ /*000f:*/ 0x00, /* ........ */
+ /*0010:*/ 0x20, /* ..#..... */
+/* --- new character quotedbl (34) starting at offset 0x0011 --- */
+ /*0011:*/ 5, 5, 3, 0, 3, /* width and bbox (w,h,x,y) */
+ /*0016:*/ 0x50, /* .#.#.... */
+ /*0017:*/ 0x50, /* .#.#.... */
+ /*0018:*/ 0x50, /* .#.#.... */
+/* --- new character numbersign (35) starting at offset 0x0019 --- */
+ /*0019:*/ 5, 5, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*001e:*/ 0x50, /* .#.#.... */
+ /*001f:*/ 0x50, /* .#.#.... */
+ /*0020:*/ 0xf8, /* #####... */
+ /*0021:*/ 0x50, /* .#.#.... */
+ /*0022:*/ 0xf8, /* #####... */
+ /*0023:*/ 0x50, /* .#.#.... */
+ /*0024:*/ 0x50, /* .#.#.... */
+/* --- new character dollar (36) starting at offset 0x0025 --- */
+ /*0025:*/ 5, 5, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*002a:*/ 0x20, /* ..#..... */
+ /*002b:*/ 0x70, /* .###.... */
+ /*002c:*/ 0xa0, /* #.#..... */
+ /*002d:*/ 0x70, /* .###.... */
+ /*002e:*/ 0x28, /* ..#.#... */
+ /*002f:*/ 0x70, /* .###.... */
+ /*0030:*/ 0x20, /* ..#..... */
+/* --- new character percent (37) starting at offset 0x0031 --- */
+ /*0031:*/ 5, 5, 5, 0, 1, /* width and bbox (w,h,x,y) */
+ /*0036:*/ 0x40, /* .#...... */
+ /*0037:*/ 0x50, /* .#.#.... */
+ /*0038:*/ 0x20, /* ..#..... */
+ /*0039:*/ 0x50, /* .#.#.... */
+ /*003a:*/ 0x10, /* ...#.... */
+/* --- new character ampersand (38) starting at offset 0x003b --- */
+ /*003b:*/ 5, 5, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0040:*/ 0x40, /* .#...... */
+ /*0041:*/ 0xa0, /* #.#..... */
+ /*0042:*/ 0xa0, /* #.#..... */
+ /*0043:*/ 0x40, /* .#...... */
+ /*0044:*/ 0xa0, /* #.#..... */
+ /*0045:*/ 0xa0, /* #.#..... */
+ /*0046:*/ 0x50, /* .#.#.... */
+/* --- new character quotesingle (39) starting at offset 0x0047 --- */
+ /*0047:*/ 5, 5, 3, 0, 3, /* width and bbox (w,h,x,y) */
+ /*004c:*/ 0x20, /* ..#..... */
+ /*004d:*/ 0x20, /* ..#..... */
+ /*004e:*/ 0x20, /* ..#..... */
+/* --- new character parenleft (40) starting at offset 0x004f --- */
+ /*004f:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0054:*/ 0x20, /* ..#..... */
+ /*0055:*/ 0x40, /* .#...... */
+ /*0056:*/ 0x40, /* .#...... */
+ /*0057:*/ 0x40, /* .#...... */
+ /*0058:*/ 0x40, /* .#...... */
+ /*0059:*/ 0x20, /* ..#..... */
+/* --- new character parenright (41) starting at offset 0x005a --- */
+ /*005a:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*005f:*/ 0x40, /* .#...... */
+ /*0060:*/ 0x20, /* ..#..... */
+ /*0061:*/ 0x20, /* ..#..... */
+ /*0062:*/ 0x20, /* ..#..... */
+ /*0063:*/ 0x20, /* ..#..... */
+ /*0064:*/ 0x40, /* .#...... */
+/* --- new character asterisk (42) starting at offset 0x0065 --- */
+ /*0065:*/ 5, 5, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*006a:*/ 0x90, /* #..#.... */
+ /*006b:*/ 0x60, /* .##..... */
+ /*006c:*/ 0xf0, /* ####.... */
+ /*006d:*/ 0x60, /* .##..... */
+ /*006e:*/ 0x90, /* #..#.... */
+/* --- new character plus (43) starting at offset 0x006f --- */
+ /*006f:*/ 5, 5, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0074:*/ 0x20, /* ..#..... */
+ /*0075:*/ 0x20, /* ..#..... */
+ /*0076:*/ 0xf8, /* #####... */
+ /*0077:*/ 0x20, /* ..#..... */
+ /*0078:*/ 0x20, /* ..#..... */
+/* --- new character comma (44) starting at offset 0x0079 --- */
+ /*0079:*/ 5, 5, 3, 0, -1, /* width and bbox (w,h,x,y) */
+ /*007e:*/ 0x30, /* ..##.... */
+ /*007f:*/ 0x20, /* ..#..... */
+ /*0080:*/ 0x40, /* .#...... */
+/* --- new character hyphen (45) starting at offset 0x0081 --- */
+ /*0081:*/ 5, 5, 1, 0, 2, /* width and bbox (w,h,x,y) */
+ /*0086:*/ 0x70, /* .###.... */
+/* --- new character period (46) starting at offset 0x0087 --- */
+ /*0087:*/ 5, 5, 3, 0, -1, /* width and bbox (w,h,x,y) */
+ /*008c:*/ 0x20, /* ..#..... */
+ /*008d:*/ 0x70, /* .###.... */
+ /*008e:*/ 0x20, /* ..#..... */
+/* --- new character slash (47) starting at offset 0x008f --- */
+ /*008f:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0094:*/ 0x10, /* ...#.... */
+ /*0095:*/ 0x10, /* ...#.... */
+ /*0096:*/ 0x20, /* ..#..... */
+ /*0097:*/ 0x40, /* .#...... */
+ /*0098:*/ 0x80, /* #....... */
+ /*0099:*/ 0x80, /* #....... */
+/* --- new character zero (48) starting at offset 0x009a --- */
+ /*009a:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*009f:*/ 0x20, /* ..#..... */
+ /*00a0:*/ 0x50, /* .#.#.... */
+ /*00a1:*/ 0x50, /* .#.#.... */
+ /*00a2:*/ 0x50, /* .#.#.... */
+ /*00a3:*/ 0x50, /* .#.#.... */
+ /*00a4:*/ 0x20, /* ..#..... */
+/* --- new character one (49) starting at offset 0x00a5 --- */
+ /*00a5:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00aa:*/ 0x20, /* ..#..... */
+ /*00ab:*/ 0x60, /* .##..... */
+ /*00ac:*/ 0x20, /* ..#..... */
+ /*00ad:*/ 0x20, /* ..#..... */
+ /*00ae:*/ 0x20, /* ..#..... */
+ /*00af:*/ 0x70, /* .###.... */
+/* --- new character two (50) starting at offset 0x00b0 --- */
+ /*00b0:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00b5:*/ 0x60, /* .##..... */
+ /*00b6:*/ 0x90, /* #..#.... */
+ /*00b7:*/ 0x10, /* ...#.... */
+ /*00b8:*/ 0x60, /* .##..... */
+ /*00b9:*/ 0x80, /* #....... */
+ /*00ba:*/ 0xf0, /* ####.... */
+/* --- new character three (51) starting at offset 0x00bb --- */
+ /*00bb:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00c0:*/ 0xf0, /* ####.... */
+ /*00c1:*/ 0x20, /* ..#..... */
+ /*00c2:*/ 0x60, /* .##..... */
+ /*00c3:*/ 0x10, /* ...#.... */
+ /*00c4:*/ 0x90, /* #..#.... */
+ /*00c5:*/ 0x60, /* .##..... */
+/* --- new character four (52) starting at offset 0x00c6 --- */
+ /*00c6:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00cb:*/ 0x20, /* ..#..... */
+ /*00cc:*/ 0x60, /* .##..... */
+ /*00cd:*/ 0xa0, /* #.#..... */
+ /*00ce:*/ 0xf0, /* ####.... */
+ /*00cf:*/ 0x20, /* ..#..... */
+ /*00d0:*/ 0x20, /* ..#..... */
+/* --- new character five (53) starting at offset 0x00d1 --- */
+ /*00d1:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00d6:*/ 0xf0, /* ####.... */
+ /*00d7:*/ 0x80, /* #....... */
+ /*00d8:*/ 0xe0, /* ###..... */
+ /*00d9:*/ 0x10, /* ...#.... */
+ /*00da:*/ 0x90, /* #..#.... */
+ /*00db:*/ 0x60, /* .##..... */
+/* --- new character six (54) starting at offset 0x00dc --- */
+ /*00dc:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00e1:*/ 0x60, /* .##..... */
+ /*00e2:*/ 0x80, /* #....... */
+ /*00e3:*/ 0xe0, /* ###..... */
+ /*00e4:*/ 0x90, /* #..#.... */
+ /*00e5:*/ 0x90, /* #..#.... */
+ /*00e6:*/ 0x60, /* .##..... */
+/* --- new character seven (55) starting at offset 0x00e7 --- */
+ /*00e7:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00ec:*/ 0xf0, /* ####.... */
+ /*00ed:*/ 0x10, /* ...#.... */
+ /*00ee:*/ 0x20, /* ..#..... */
+ /*00ef:*/ 0x20, /* ..#..... */
+ /*00f0:*/ 0x40, /* .#...... */
+ /*00f1:*/ 0x40, /* .#...... */
+/* --- new character eight (56) starting at offset 0x00f2 --- */
+ /*00f2:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00f7:*/ 0x60, /* .##..... */
+ /*00f8:*/ 0x90, /* #..#.... */
+ /*00f9:*/ 0x60, /* .##..... */
+ /*00fa:*/ 0x90, /* #..#.... */
+ /*00fb:*/ 0x90, /* #..#.... */
+ /*00fc:*/ 0x60, /* .##..... */
+/* --- new character nine (57) starting at offset 0x00fd --- */
+ /*00fd:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0102:*/ 0x60, /* .##..... */
+ /*0103:*/ 0x90, /* #..#.... */
+ /*0104:*/ 0x90, /* #..#.... */
+ /*0105:*/ 0x70, /* .###.... */
+ /*0106:*/ 0x10, /* ...#.... */
+ /*0107:*/ 0x60, /* .##..... */
+/* --- new character colon (58) starting at offset 0x0108 --- */
+ /*0108:*/ 5, 5, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*010d:*/ 0x60, /* .##..... */
+ /*010e:*/ 0x60, /* .##..... */
+ /*010f:*/ 0x00, /* ........ */
+ /*0110:*/ 0x60, /* .##..... */
+ /*0111:*/ 0x60, /* .##..... */
+/* --- new character semicolon (59) starting at offset 0x0112 --- */
+ /*0112:*/ 5, 5, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0117:*/ 0x30, /* ..##.... */
+ /*0118:*/ 0x30, /* ..##.... */
+ /*0119:*/ 0x00, /* ........ */
+ /*011a:*/ 0x30, /* ..##.... */
+ /*011b:*/ 0x20, /* ..#..... */
+ /*011c:*/ 0x40, /* .#...... */
+/* --- new character less (60) starting at offset 0x011d --- */
+ /*011d:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0122:*/ 0x10, /* ...#.... */
+ /*0123:*/ 0x20, /* ..#..... */
+ /*0124:*/ 0x40, /* .#...... */
+ /*0125:*/ 0x40, /* .#...... */
+ /*0126:*/ 0x20, /* ..#..... */
+ /*0127:*/ 0x10, /* ...#.... */
+/* --- new character equal (61) starting at offset 0x0128 --- */
+ /*0128:*/ 5, 5, 3, 0, 1, /* width and bbox (w,h,x,y) */
+ /*012d:*/ 0xf0, /* ####.... */
+ /*012e:*/ 0x00, /* ........ */
+ /*012f:*/ 0xf0, /* ####.... */
+/* --- new character greater (62) starting at offset 0x0130 --- */
+ /*0130:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0135:*/ 0x40, /* .#...... */
+ /*0136:*/ 0x20, /* ..#..... */
+ /*0137:*/ 0x10, /* ...#.... */
+ /*0138:*/ 0x10, /* ...#.... */
+ /*0139:*/ 0x20, /* ..#..... */
+ /*013a:*/ 0x40, /* .#...... */
+/* --- new character question (63) starting at offset 0x013b --- */
+ /*013b:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0140:*/ 0x20, /* ..#..... */
+ /*0141:*/ 0x50, /* .#.#.... */
+ /*0142:*/ 0x10, /* ...#.... */
+ /*0143:*/ 0x20, /* ..#..... */
+ /*0144:*/ 0x00, /* ........ */
+ /*0145:*/ 0x20, /* ..#..... */
+/* --- new character at (64) starting at offset 0x0146 --- */
+ /*0146:*/ 5, 5, 8, 0, -1, /* width and bbox (w,h,x,y) */
+ /*014b:*/ 0x30, /* ..##.... */
+ /*014c:*/ 0x48, /* .#..#... */
+ /*014d:*/ 0x98, /* #..##... */
+ /*014e:*/ 0xa8, /* #.#.#... */
+ /*014f:*/ 0xa8, /* #.#.#... */
+ /*0150:*/ 0x90, /* #..#.... */
+ /*0151:*/ 0x40, /* .#...... */
+ /*0152:*/ 0x30, /* ..##.... */
+/* --- new character A (65) starting at offset 0x0153 --- */
+ /*0153:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0158:*/ 0x60, /* .##..... */
+ /*0159:*/ 0x90, /* #..#.... */
+ /*015a:*/ 0x90, /* #..#.... */
+ /*015b:*/ 0xf0, /* ####.... */
+ /*015c:*/ 0x90, /* #..#.... */
+ /*015d:*/ 0x90, /* #..#.... */
+/* --- new character B (66) starting at offset 0x015e --- */
+ /*015e:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0163:*/ 0xe0, /* ###..... */
+ /*0164:*/ 0x90, /* #..#.... */
+ /*0165:*/ 0xe0, /* ###..... */
+ /*0166:*/ 0x90, /* #..#.... */
+ /*0167:*/ 0x90, /* #..#.... */
+ /*0168:*/ 0xe0, /* ###..... */
+/* --- new character C (67) starting at offset 0x0169 --- */
+ /*0169:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*016e:*/ 0x60, /* .##..... */
+ /*016f:*/ 0x90, /* #..#.... */
+ /*0170:*/ 0x80, /* #....... */
+ /*0171:*/ 0x80, /* #....... */
+ /*0172:*/ 0x90, /* #..#.... */
+ /*0173:*/ 0x60, /* .##..... */
+/* --- new character D (68) starting at offset 0x0174 --- */
+ /*0174:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0179:*/ 0xe0, /* ###..... */
+ /*017a:*/ 0x90, /* #..#.... */
+ /*017b:*/ 0x90, /* #..#.... */
+ /*017c:*/ 0x90, /* #..#.... */
+ /*017d:*/ 0x90, /* #..#.... */
+ /*017e:*/ 0xe0, /* ###..... */
+/* --- new character E (69) starting at offset 0x017f --- */
+ /*017f:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0184:*/ 0xf0, /* ####.... */
+ /*0185:*/ 0x80, /* #....... */
+ /*0186:*/ 0xe0, /* ###..... */
+ /*0187:*/ 0x80, /* #....... */
+ /*0188:*/ 0x80, /* #....... */
+ /*0189:*/ 0xf0, /* ####.... */
+/* --- new character F (70) starting at offset 0x018a --- */
+ /*018a:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*018f:*/ 0xf0, /* ####.... */
+ /*0190:*/ 0x80, /* #....... */
+ /*0191:*/ 0xe0, /* ###..... */
+ /*0192:*/ 0x80, /* #....... */
+ /*0193:*/ 0x80, /* #....... */
+ /*0194:*/ 0x80, /* #....... */
+/* --- new character G (71) starting at offset 0x0195 --- */
+ /*0195:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*019a:*/ 0x60, /* .##..... */
+ /*019b:*/ 0x90, /* #..#.... */
+ /*019c:*/ 0x80, /* #....... */
+ /*019d:*/ 0xb0, /* #.##.... */
+ /*019e:*/ 0x90, /* #..#.... */
+ /*019f:*/ 0x60, /* .##..... */
+/* --- new character H (72) starting at offset 0x01a0 --- */
+ /*01a0:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01a5:*/ 0x90, /* #..#.... */
+ /*01a6:*/ 0x90, /* #..#.... */
+ /*01a7:*/ 0xf0, /* ####.... */
+ /*01a8:*/ 0x90, /* #..#.... */
+ /*01a9:*/ 0x90, /* #..#.... */
+ /*01aa:*/ 0x90, /* #..#.... */
+/* --- new character I (73) starting at offset 0x01ab --- */
+ /*01ab:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01b0:*/ 0x70, /* .###.... */
+ /*01b1:*/ 0x20, /* ..#..... */
+ /*01b2:*/ 0x20, /* ..#..... */
+ /*01b3:*/ 0x20, /* ..#..... */
+ /*01b4:*/ 0x20, /* ..#..... */
+ /*01b5:*/ 0x70, /* .###.... */
+/* --- new character J (74) starting at offset 0x01b6 --- */
+ /*01b6:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01bb:*/ 0x70, /* .###.... */
+ /*01bc:*/ 0x20, /* ..#..... */
+ /*01bd:*/ 0x20, /* ..#..... */
+ /*01be:*/ 0x20, /* ..#..... */
+ /*01bf:*/ 0xa0, /* #.#..... */
+ /*01c0:*/ 0x40, /* .#...... */
+/* --- new character K (75) starting at offset 0x01c1 --- */
+ /*01c1:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01c6:*/ 0x90, /* #..#.... */
+ /*01c7:*/ 0xa0, /* #.#..... */
+ /*01c8:*/ 0xc0, /* ##...... */
+ /*01c9:*/ 0xa0, /* #.#..... */
+ /*01ca:*/ 0xa0, /* #.#..... */
+ /*01cb:*/ 0x90, /* #..#.... */
+/* --- new character L (76) starting at offset 0x01cc --- */
+ /*01cc:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01d1:*/ 0x80, /* #....... */
+ /*01d2:*/ 0x80, /* #....... */
+ /*01d3:*/ 0x80, /* #....... */
+ /*01d4:*/ 0x80, /* #....... */
+ /*01d5:*/ 0x80, /* #....... */
+ /*01d6:*/ 0xf0, /* ####.... */
+/* --- new character M (77) starting at offset 0x01d7 --- */
+ /*01d7:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01dc:*/ 0x90, /* #..#.... */
+ /*01dd:*/ 0xf0, /* ####.... */
+ /*01de:*/ 0xf0, /* ####.... */
+ /*01df:*/ 0x90, /* #..#.... */
+ /*01e0:*/ 0x90, /* #..#.... */
+ /*01e1:*/ 0x90, /* #..#.... */
+/* --- new character N (78) starting at offset 0x01e2 --- */
+ /*01e2:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01e7:*/ 0x90, /* #..#.... */
+ /*01e8:*/ 0xd0, /* ##.#.... */
+ /*01e9:*/ 0xf0, /* ####.... */
+ /*01ea:*/ 0xb0, /* #.##.... */
+ /*01eb:*/ 0xb0, /* #.##.... */
+ /*01ec:*/ 0x90, /* #..#.... */
+/* --- new character O (79) starting at offset 0x01ed --- */
+ /*01ed:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01f2:*/ 0x60, /* .##..... */
+ /*01f3:*/ 0x90, /* #..#.... */
+ /*01f4:*/ 0x90, /* #..#.... */
+ /*01f5:*/ 0x90, /* #..#.... */
+ /*01f6:*/ 0x90, /* #..#.... */
+ /*01f7:*/ 0x60, /* .##..... */
+/* --- new character P (80) starting at offset 0x01f8 --- */
+ /*01f8:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01fd:*/ 0xe0, /* ###..... */
+ /*01fe:*/ 0x90, /* #..#.... */
+ /*01ff:*/ 0x90, /* #..#.... */
+ /*0200:*/ 0xe0, /* ###..... */
+ /*0201:*/ 0x80, /* #....... */
+ /*0202:*/ 0x80, /* #....... */
+/* --- new character Q (81) starting at offset 0x0203 --- */
+ /*0203:*/ 5, 5, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0208:*/ 0x60, /* .##..... */
+ /*0209:*/ 0x90, /* #..#.... */
+ /*020a:*/ 0x90, /* #..#.... */
+ /*020b:*/ 0xd0, /* ##.#.... */
+ /*020c:*/ 0xb0, /* #.##.... */
+ /*020d:*/ 0x60, /* .##..... */
+ /*020e:*/ 0x10, /* ...#.... */
+/* --- new character R (82) starting at offset 0x020f --- */
+ /*020f:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0214:*/ 0xe0, /* ###..... */
+ /*0215:*/ 0x90, /* #..#.... */
+ /*0216:*/ 0x90, /* #..#.... */
+ /*0217:*/ 0xe0, /* ###..... */
+ /*0218:*/ 0x90, /* #..#.... */
+ /*0219:*/ 0x90, /* #..#.... */
+/* --- new character S (83) starting at offset 0x021a --- */
+ /*021a:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*021f:*/ 0x60, /* .##..... */
+ /*0220:*/ 0x90, /* #..#.... */
+ /*0221:*/ 0x40, /* .#...... */
+ /*0222:*/ 0x20, /* ..#..... */
+ /*0223:*/ 0x90, /* #..#.... */
+ /*0224:*/ 0x60, /* .##..... */
+/* --- new character T (84) starting at offset 0x0225 --- */
+ /*0225:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*022a:*/ 0x70, /* .###.... */
+ /*022b:*/ 0x20, /* ..#..... */
+ /*022c:*/ 0x20, /* ..#..... */
+ /*022d:*/ 0x20, /* ..#..... */
+ /*022e:*/ 0x20, /* ..#..... */
+ /*022f:*/ 0x20, /* ..#..... */
+/* --- new character U (85) starting at offset 0x0230 --- */
+ /*0230:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0235:*/ 0x90, /* #..#.... */
+ /*0236:*/ 0x90, /* #..#.... */
+ /*0237:*/ 0x90, /* #..#.... */
+ /*0238:*/ 0x90, /* #..#.... */
+ /*0239:*/ 0x90, /* #..#.... */
+ /*023a:*/ 0x60, /* .##..... */
+/* --- new character V (86) starting at offset 0x023b --- */
+ /*023b:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0240:*/ 0x90, /* #..#.... */
+ /*0241:*/ 0x90, /* #..#.... */
+ /*0242:*/ 0x90, /* #..#.... */
+ /*0243:*/ 0x90, /* #..#.... */
+ /*0244:*/ 0x60, /* .##..... */
+ /*0245:*/ 0x60, /* .##..... */
+/* --- new character W (87) starting at offset 0x0246 --- */
+ /*0246:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*024b:*/ 0x90, /* #..#.... */
+ /*024c:*/ 0x90, /* #..#.... */
+ /*024d:*/ 0x90, /* #..#.... */
+ /*024e:*/ 0xf0, /* ####.... */
+ /*024f:*/ 0xf0, /* ####.... */
+ /*0250:*/ 0x90, /* #..#.... */
+/* --- new character X (88) starting at offset 0x0251 --- */
+ /*0251:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0256:*/ 0x90, /* #..#.... */
+ /*0257:*/ 0x90, /* #..#.... */
+ /*0258:*/ 0x60, /* .##..... */
+ /*0259:*/ 0x60, /* .##..... */
+ /*025a:*/ 0x90, /* #..#.... */
+ /*025b:*/ 0x90, /* #..#.... */
+/* --- new character Y (89) starting at offset 0x025c --- */
+ /*025c:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0261:*/ 0x88, /* #...#... */
+ /*0262:*/ 0x88, /* #...#... */
+ /*0263:*/ 0x50, /* .#.#.... */
+ /*0264:*/ 0x20, /* ..#..... */
+ /*0265:*/ 0x20, /* ..#..... */
+ /*0266:*/ 0x20, /* ..#..... */
+/* --- new character Z (90) starting at offset 0x0267 --- */
+ /*0267:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*026c:*/ 0xf0, /* ####.... */
+ /*026d:*/ 0x10, /* ...#.... */
+ /*026e:*/ 0x20, /* ..#..... */
+ /*026f:*/ 0x40, /* .#...... */
+ /*0270:*/ 0x80, /* #....... */
+ /*0271:*/ 0xf0, /* ####.... */
+/* --- new character bracketleft (91) starting at offset 0x0272 --- */
+ /*0272:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0277:*/ 0x70, /* .###.... */
+ /*0278:*/ 0x40, /* .#...... */
+ /*0279:*/ 0x40, /* .#...... */
+ /*027a:*/ 0x40, /* .#...... */
+ /*027b:*/ 0x40, /* .#...... */
+ /*027c:*/ 0x70, /* .###.... */
+/* --- new character backslash (92) starting at offset 0x027d --- */
+ /*027d:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0282:*/ 0x80, /* #....... */
+ /*0283:*/ 0x80, /* #....... */
+ /*0284:*/ 0x40, /* .#...... */
+ /*0285:*/ 0x20, /* ..#..... */
+ /*0286:*/ 0x10, /* ...#.... */
+ /*0287:*/ 0x10, /* ...#.... */
+/* --- new character bracketright (93) starting at offset 0x0288 --- */
+ /*0288:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*028d:*/ 0x70, /* .###.... */
+ /*028e:*/ 0x10, /* ...#.... */
+ /*028f:*/ 0x10, /* ...#.... */
+ /*0290:*/ 0x10, /* ...#.... */
+ /*0291:*/ 0x10, /* ...#.... */
+ /*0292:*/ 0x70, /* .###.... */
+/* --- new character asciicircum (94) starting at offset 0x0293 --- */
+ /*0293:*/ 5, 5, 2, 0, 4, /* width and bbox (w,h,x,y) */
+ /*0298:*/ 0x20, /* ..#..... */
+ /*0299:*/ 0x50, /* .#.#.... */
+/* --- new character underscore (95) starting at offset 0x029a --- */
+ /*029a:*/ 5, 5, 1, 0, -1, /* width and bbox (w,h,x,y) */
+ /*029f:*/ 0xf0, /* ####.... */
+/* --- new character grave (96) starting at offset 0x02a0 --- */
+ /*02a0:*/ 5, 5, 2, 0, 4, /* width and bbox (w,h,x,y) */
+ /*02a5:*/ 0x40, /* .#...... */
+ /*02a6:*/ 0x20, /* ..#..... */
+/* --- new character a (97) starting at offset 0x02a7 --- */
+ /*02a7:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02ac:*/ 0x70, /* .###.... */
+ /*02ad:*/ 0x90, /* #..#.... */
+ /*02ae:*/ 0x90, /* #..#.... */
+ /*02af:*/ 0x70, /* .###.... */
+/* --- new character b (98) starting at offset 0x02b0 --- */
+ /*02b0:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02b5:*/ 0x80, /* #....... */
+ /*02b6:*/ 0x80, /* #....... */
+ /*02b7:*/ 0xe0, /* ###..... */
+ /*02b8:*/ 0x90, /* #..#.... */
+ /*02b9:*/ 0x90, /* #..#.... */
+ /*02ba:*/ 0xe0, /* ###..... */
+/* --- new character c (99) starting at offset 0x02bb --- */
+ /*02bb:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02c0:*/ 0x30, /* ..##.... */
+ /*02c1:*/ 0x40, /* .#...... */
+ /*02c2:*/ 0x40, /* .#...... */
+ /*02c3:*/ 0x30, /* ..##.... */
+/* --- new character d (100) starting at offset 0x02c4 --- */
+ /*02c4:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02c9:*/ 0x10, /* ...#.... */
+ /*02ca:*/ 0x10, /* ...#.... */
+ /*02cb:*/ 0x70, /* .###.... */
+ /*02cc:*/ 0x90, /* #..#.... */
+ /*02cd:*/ 0x90, /* #..#.... */
+ /*02ce:*/ 0x70, /* .###.... */
+/* --- new character e (101) starting at offset 0x02cf --- */
+ /*02cf:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02d4:*/ 0x60, /* .##..... */
+ /*02d5:*/ 0xb0, /* #.##.... */
+ /*02d6:*/ 0xc0, /* ##...... */
+ /*02d7:*/ 0x60, /* .##..... */
+/* --- new character f (102) starting at offset 0x02d8 --- */
+ /*02d8:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02dd:*/ 0x20, /* ..#..... */
+ /*02de:*/ 0x50, /* .#.#.... */
+ /*02df:*/ 0x40, /* .#...... */
+ /*02e0:*/ 0xe0, /* ###..... */
+ /*02e1:*/ 0x40, /* .#...... */
+ /*02e2:*/ 0x40, /* .#...... */
+/* --- new character g (103) starting at offset 0x02e3 --- */
+ /*02e3:*/ 5, 5, 5, 0, -1, /* width and bbox (w,h,x,y) */
+ /*02e8:*/ 0x60, /* .##..... */
+ /*02e9:*/ 0x90, /* #..#.... */
+ /*02ea:*/ 0x70, /* .###.... */
+ /*02eb:*/ 0x10, /* ...#.... */
+ /*02ec:*/ 0x60, /* .##..... */
+/* --- new character h (104) starting at offset 0x02ed --- */
+ /*02ed:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02f2:*/ 0x80, /* #....... */
+ /*02f3:*/ 0x80, /* #....... */
+ /*02f4:*/ 0xe0, /* ###..... */
+ /*02f5:*/ 0x90, /* #..#.... */
+ /*02f6:*/ 0x90, /* #..#.... */
+ /*02f7:*/ 0x90, /* #..#.... */
+/* --- new character i (105) starting at offset 0x02f8 --- */
+ /*02f8:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02fd:*/ 0x20, /* ..#..... */
+ /*02fe:*/ 0x00, /* ........ */
+ /*02ff:*/ 0x60, /* .##..... */
+ /*0300:*/ 0x20, /* ..#..... */
+ /*0301:*/ 0x20, /* ..#..... */
+ /*0302:*/ 0x70, /* .###.... */
+/* --- new character j (106) starting at offset 0x0303 --- */
+ /*0303:*/ 5, 5, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0308:*/ 0x10, /* ...#.... */
+ /*0309:*/ 0x00, /* ........ */
+ /*030a:*/ 0x10, /* ...#.... */
+ /*030b:*/ 0x10, /* ...#.... */
+ /*030c:*/ 0x10, /* ...#.... */
+ /*030d:*/ 0x50, /* .#.#.... */
+ /*030e:*/ 0x20, /* ..#..... */
+/* --- new character k (107) starting at offset 0x030f --- */
+ /*030f:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0314:*/ 0x80, /* #....... */
+ /*0315:*/ 0x80, /* #....... */
+ /*0316:*/ 0x90, /* #..#.... */
+ /*0317:*/ 0xe0, /* ###..... */
+ /*0318:*/ 0x90, /* #..#.... */
+ /*0319:*/ 0x90, /* #..#.... */
+/* --- new character l (108) starting at offset 0x031a --- */
+ /*031a:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*031f:*/ 0x60, /* .##..... */
+ /*0320:*/ 0x20, /* ..#..... */
+ /*0321:*/ 0x20, /* ..#..... */
+ /*0322:*/ 0x20, /* ..#..... */
+ /*0323:*/ 0x20, /* ..#..... */
+ /*0324:*/ 0x70, /* .###.... */
+/* --- new character m (109) starting at offset 0x0325 --- */
+ /*0325:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*032a:*/ 0xd0, /* ##.#.... */
+ /*032b:*/ 0xa8, /* #.#.#... */
+ /*032c:*/ 0xa8, /* #.#.#... */
+ /*032d:*/ 0xa8, /* #.#.#... */
+/* --- new character n (110) starting at offset 0x032e --- */
+ /*032e:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0333:*/ 0xe0, /* ###..... */
+ /*0334:*/ 0x90, /* #..#.... */
+ /*0335:*/ 0x90, /* #..#.... */
+ /*0336:*/ 0x90, /* #..#.... */
+/* --- new character o (111) starting at offset 0x0337 --- */
+ /*0337:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*033c:*/ 0x60, /* .##..... */
+ /*033d:*/ 0x90, /* #..#.... */
+ /*033e:*/ 0x90, /* #..#.... */
+ /*033f:*/ 0x60, /* .##..... */
+/* --- new character p (112) starting at offset 0x0340 --- */
+ /*0340:*/ 5, 5, 5, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0345:*/ 0xe0, /* ###..... */
+ /*0346:*/ 0x90, /* #..#.... */
+ /*0347:*/ 0xe0, /* ###..... */
+ /*0348:*/ 0x80, /* #....... */
+ /*0349:*/ 0x80, /* #....... */
+/* --- new character q (113) starting at offset 0x034a --- */
+ /*034a:*/ 5, 5, 5, 0, -1, /* width and bbox (w,h,x,y) */
+ /*034f:*/ 0x70, /* .###.... */
+ /*0350:*/ 0x90, /* #..#.... */
+ /*0351:*/ 0x70, /* .###.... */
+ /*0352:*/ 0x10, /* ...#.... */
+ /*0353:*/ 0x10, /* ...#.... */
+/* --- new character r (114) starting at offset 0x0354 --- */
+ /*0354:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0359:*/ 0xa0, /* #.#..... */
+ /*035a:*/ 0xd0, /* ##.#.... */
+ /*035b:*/ 0x80, /* #....... */
+ /*035c:*/ 0x80, /* #....... */
+/* --- new character s (115) starting at offset 0x035d --- */
+ /*035d:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0362:*/ 0x30, /* ..##.... */
+ /*0363:*/ 0x60, /* .##..... */
+ /*0364:*/ 0x10, /* ...#.... */
+ /*0365:*/ 0x60, /* .##..... */
+/* --- new character t (116) starting at offset 0x0366 --- */
+ /*0366:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*036b:*/ 0x40, /* .#...... */
+ /*036c:*/ 0x40, /* .#...... */
+ /*036d:*/ 0xe0, /* ###..... */
+ /*036e:*/ 0x40, /* .#...... */
+ /*036f:*/ 0x50, /* .#.#.... */
+ /*0370:*/ 0x20, /* ..#..... */
+/* --- new character u (117) starting at offset 0x0371 --- */
+ /*0371:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0376:*/ 0x90, /* #..#.... */
+ /*0377:*/ 0x90, /* #..#.... */
+ /*0378:*/ 0x90, /* #..#.... */
+ /*0379:*/ 0x70, /* .###.... */
+/* --- new character v (118) starting at offset 0x037a --- */
+ /*037a:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*037f:*/ 0x50, /* .#.#.... */
+ /*0380:*/ 0x50, /* .#.#.... */
+ /*0381:*/ 0x50, /* .#.#.... */
+ /*0382:*/ 0x20, /* ..#..... */
+/* --- new character w (119) starting at offset 0x0383 --- */
+ /*0383:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0388:*/ 0x88, /* #...#... */
+ /*0389:*/ 0xa8, /* #.#.#... */
+ /*038a:*/ 0xa8, /* #.#.#... */
+ /*038b:*/ 0x50, /* .#.#.... */
+/* --- new character x (120) starting at offset 0x038c --- */
+ /*038c:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0391:*/ 0x90, /* #..#.... */
+ /*0392:*/ 0x60, /* .##..... */
+ /*0393:*/ 0x60, /* .##..... */
+ /*0394:*/ 0x90, /* #..#.... */
+/* --- new character y (121) starting at offset 0x0395 --- */
+ /*0395:*/ 5, 5, 5, 0, -1, /* width and bbox (w,h,x,y) */
+ /*039a:*/ 0x90, /* #..#.... */
+ /*039b:*/ 0x90, /* #..#.... */
+ /*039c:*/ 0x70, /* .###.... */
+ /*039d:*/ 0x90, /* #..#.... */
+ /*039e:*/ 0x60, /* .##..... */
+/* --- new character z (122) starting at offset 0x039f --- */
+ /*039f:*/ 5, 5, 4, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03a4:*/ 0xf0, /* ####.... */
+ /*03a5:*/ 0x20, /* ..#..... */
+ /*03a6:*/ 0x40, /* .#...... */
+ /*03a7:*/ 0xf0, /* ####.... */
+/* --- new character braceleft (123) starting at offset 0x03a8 --- */
+ /*03a8:*/ 5, 5, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03ad:*/ 0x30, /* ..##.... */
+ /*03ae:*/ 0x40, /* .#...... */
+ /*03af:*/ 0x20, /* ..#..... */
+ /*03b0:*/ 0xc0, /* ##...... */
+ /*03b1:*/ 0x20, /* ..#..... */
+ /*03b2:*/ 0x40, /* .#...... */
+ /*03b3:*/ 0x30, /* ..##.... */
+/* --- new character bar (124) starting at offset 0x03b4 --- */
+ /*03b4:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03b9:*/ 0x20, /* ..#..... */
+ /*03ba:*/ 0x20, /* ..#..... */
+ /*03bb:*/ 0x20, /* ..#..... */
+ /*03bc:*/ 0x20, /* ..#..... */
+ /*03bd:*/ 0x20, /* ..#..... */
+ /*03be:*/ 0x20, /* ..#..... */
+/* --- new character braceright (125) starting at offset 0x03bf --- */
+ /*03bf:*/ 5, 5, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03c4:*/ 0xc0, /* ##...... */
+ /*03c5:*/ 0x20, /* ..#..... */
+ /*03c6:*/ 0x40, /* .#...... */
+ /*03c7:*/ 0x30, /* ..##.... */
+ /*03c8:*/ 0x40, /* .#...... */
+ /*03c9:*/ 0x20, /* ..#..... */
+ /*03ca:*/ 0xc0, /* ##...... */
+/* --- new character asciitilde (126) starting at offset 0x03cb --- */
+ /*03cb:*/ 5, 5, 2, 0, 4, /* width and bbox (w,h,x,y) */
+ /*03d0:*/ 0x50, /* .#.#.... */
+ /*03d1:*/ 0xa0, /* #.#..... */
+};
+static const uint16_t font_5x8_offsets[] = {
+0x0000 /* space */,
+ 0x0006 /* exclam */,
+ 0x0011 /* quotedbl */,
+ 0x0019 /* numbersign */,
+ 0x0025 /* dollar */,
+ 0x0031 /* percent */,
+ 0x003b /* ampersand */,
+ 0x0047 /* quotesingle */,
+ 0x004f /* parenleft */,
+ 0x005a /* parenright */,
+ 0x0065 /* asterisk */,
+ 0x006f /* plus */,
+ 0x0079 /* comma */,
+ 0x0081 /* hyphen */,
+ 0x0087 /* period */,
+ 0x008f /* slash */,
+ 0x009a /* zero */,
+ 0x00a5 /* one */,
+ 0x00b0 /* two */,
+ 0x00bb /* three */,
+ 0x00c6 /* four */,
+ 0x00d1 /* five */,
+ 0x00dc /* six */,
+ 0x00e7 /* seven */,
+ 0x00f2 /* eight */,
+ 0x00fd /* nine */,
+ 0x0108 /* colon */,
+ 0x0112 /* semicolon */,
+ 0x011d /* less */,
+ 0x0128 /* equal */,
+ 0x0130 /* greater */,
+ 0x013b /* question */,
+ 0x0146 /* at */,
+ 0x0153 /* A */,
+ 0x015e /* B */,
+ 0x0169 /* C */,
+ 0x0174 /* D */,
+ 0x017f /* E */,
+ 0x018a /* F */,
+ 0x0195 /* G */,
+ 0x01a0 /* H */,
+ 0x01ab /* I */,
+ 0x01b6 /* J */,
+ 0x01c1 /* K */,
+ 0x01cc /* L */,
+ 0x01d7 /* M */,
+ 0x01e2 /* N */,
+ 0x01ed /* O */,
+ 0x01f8 /* P */,
+ 0x0203 /* Q */,
+ 0x020f /* R */,
+ 0x021a /* S */,
+ 0x0225 /* T */,
+ 0x0230 /* U */,
+ 0x023b /* V */,
+ 0x0246 /* W */,
+ 0x0251 /* X */,
+ 0x025c /* Y */,
+ 0x0267 /* Z */,
+ 0x0272 /* bracketleft */,
+ 0x027d /* backslash */,
+ 0x0288 /* bracketright */,
+ 0x0293 /* asciicircum */,
+ 0x029a /* underscore */,
+ 0x02a0 /* grave */,
+ 0x02a7 /* a */,
+ 0x02b0 /* b */,
+ 0x02bb /* c */,
+ 0x02c4 /* d */,
+ 0x02cf /* e */,
+ 0x02d8 /* f */,
+ 0x02e3 /* g */,
+ 0x02ed /* h */,
+ 0x02f8 /* i */,
+ 0x0303 /* j */,
+ 0x030f /* k */,
+ 0x031a /* l */,
+ 0x0325 /* m */,
+ 0x032e /* n */,
+ 0x0337 /* o */,
+ 0x0340 /* p */,
+ 0x034a /* q */,
+ 0x0354 /* r */,
+ 0x035d /* s */,
+ 0x0366 /* t */,
+ 0x0371 /* u */,
+ 0x037a /* v */,
+ 0x0383 /* w */,
+ 0x038c /* x */,
+ 0x0395 /* y */,
+ 0x039f /* z */,
+ 0x03a8 /* braceleft */,
+ 0x03b4 /* bar */,
+ 0x03bf /* braceright */,
+ 0x03cb /* asciitilde */,
+ 0xffff /* (no glyph) */
+};
+const struct fb_font font_5x8 = {
+ .height = 8,
+ .ascent = 7,
+ .firstchar = 32, /* space */
+ .lastchar = 127, /* ? */
+ .chardata = font_5x8_data,
+ .charoffs = font_5x8_offsets,
+};
diff --git a/src/target/firmware/fb/c64.c b/src/target/firmware/fb/c64.c
new file mode 100644
index 00000000..82ebfa35
--- /dev/null
+++ b/src/target/firmware/fb/c64.c
@@ -0,0 +1,1069 @@
+#include <fb/font.h>
+static const uint8_t font_c64_data[] = {
+/* --- new character ' ' (32) starting at offset 0x0000 --- */
+ /*0000:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x00, /* ........ */
+ /*0006:*/ 0x00, /* ........ */
+ /*0007:*/ 0x00, /* ........ */
+ /*0008:*/ 0x00, /* ........ */
+ /*0009:*/ 0x00, /* ........ */
+ /*000a:*/ 0x00, /* ........ */
+ /*000b:*/ 0x00, /* ........ */
+ /*000c:*/ 0x00, /* ........ */
+/* --- new character '!' (33) starting at offset 0x000d --- */
+ /*000d:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0012:*/ 0x18, /* ...##... */
+ /*0013:*/ 0x18, /* ...##... */
+ /*0014:*/ 0x18, /* ...##... */
+ /*0015:*/ 0x18, /* ...##... */
+ /*0016:*/ 0x00, /* ........ */
+ /*0017:*/ 0x00, /* ........ */
+ /*0018:*/ 0x18, /* ...##... */
+ /*0019:*/ 0x00, /* ........ */
+/* --- new character '"' (34) starting at offset 0x001a --- */
+ /*001a:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*001f:*/ 0x66, /* .##..##. */
+ /*0020:*/ 0x66, /* .##..##. */
+ /*0021:*/ 0x66, /* .##..##. */
+ /*0022:*/ 0x00, /* ........ */
+ /*0023:*/ 0x00, /* ........ */
+ /*0024:*/ 0x00, /* ........ */
+ /*0025:*/ 0x00, /* ........ */
+ /*0026:*/ 0x00, /* ........ */
+/* --- new character '#' (35) starting at offset 0x0027 --- */
+ /*0027:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*002c:*/ 0x66, /* .##..##. */
+ /*002d:*/ 0x66, /* .##..##. */
+ /*002e:*/ 0xff, /* ######## */
+ /*002f:*/ 0x66, /* .##..##. */
+ /*0030:*/ 0xff, /* ######## */
+ /*0031:*/ 0x66, /* .##..##. */
+ /*0032:*/ 0x66, /* .##..##. */
+ /*0033:*/ 0x00, /* ........ */
+/* --- new character '$' (36) starting at offset 0x0034 --- */
+ /*0034:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0039:*/ 0x18, /* ...##... */
+ /*003a:*/ 0x3e, /* ..#####. */
+ /*003b:*/ 0x60, /* .##..... */
+ /*003c:*/ 0x3c, /* ..####.. */
+ /*003d:*/ 0x06, /* .....##. */
+ /*003e:*/ 0x7c, /* .#####.. */
+ /*003f:*/ 0x18, /* ...##... */
+ /*0040:*/ 0x00, /* ........ */
+/* --- new character '%' (37) starting at offset 0x0041 --- */
+ /*0041:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0046:*/ 0x62, /* .##...#. */
+ /*0047:*/ 0x66, /* .##..##. */
+ /*0048:*/ 0x0c, /* ....##.. */
+ /*0049:*/ 0x18, /* ...##... */
+ /*004a:*/ 0x30, /* ..##.... */
+ /*004b:*/ 0x66, /* .##..##. */
+ /*004c:*/ 0x46, /* .#...##. */
+ /*004d:*/ 0x00, /* ........ */
+/* --- new character '&' (38) starting at offset 0x004e --- */
+ /*004e:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0053:*/ 0x3c, /* ..####.. */
+ /*0054:*/ 0x66, /* .##..##. */
+ /*0055:*/ 0x3c, /* ..####.. */
+ /*0056:*/ 0x38, /* ..###... */
+ /*0057:*/ 0x67, /* .##..### */
+ /*0058:*/ 0x66, /* .##..##. */
+ /*0059:*/ 0x3f, /* ..###### */
+ /*005a:*/ 0x00, /* ........ */
+/* --- new character ''' (39) starting at offset 0x005b --- */
+ /*005b:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0060:*/ 0x06, /* .....##. */
+ /*0061:*/ 0x0c, /* ....##.. */
+ /*0062:*/ 0x18, /* ...##... */
+ /*0063:*/ 0x00, /* ........ */
+ /*0064:*/ 0x00, /* ........ */
+ /*0065:*/ 0x00, /* ........ */
+ /*0066:*/ 0x00, /* ........ */
+ /*0067:*/ 0x00, /* ........ */
+/* --- new character '(' (40) starting at offset 0x0068 --- */
+ /*0068:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*006d:*/ 0x0c, /* ....##.. */
+ /*006e:*/ 0x18, /* ...##... */
+ /*006f:*/ 0x30, /* ..##.... */
+ /*0070:*/ 0x30, /* ..##.... */
+ /*0071:*/ 0x30, /* ..##.... */
+ /*0072:*/ 0x18, /* ...##... */
+ /*0073:*/ 0x0c, /* ....##.. */
+ /*0074:*/ 0x00, /* ........ */
+/* --- new character ')' (41) starting at offset 0x0075 --- */
+ /*0075:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*007a:*/ 0x30, /* ..##.... */
+ /*007b:*/ 0x18, /* ...##... */
+ /*007c:*/ 0x0c, /* ....##.. */
+ /*007d:*/ 0x0c, /* ....##.. */
+ /*007e:*/ 0x0c, /* ....##.. */
+ /*007f:*/ 0x18, /* ...##... */
+ /*0080:*/ 0x30, /* ..##.... */
+ /*0081:*/ 0x00, /* ........ */
+/* --- new character '*' (42) starting at offset 0x0082 --- */
+ /*0082:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0087:*/ 0x00, /* ........ */
+ /*0088:*/ 0x66, /* .##..##. */
+ /*0089:*/ 0x3c, /* ..####.. */
+ /*008a:*/ 0xff, /* ######## */
+ /*008b:*/ 0x3c, /* ..####.. */
+ /*008c:*/ 0x66, /* .##..##. */
+ /*008d:*/ 0x00, /* ........ */
+ /*008e:*/ 0x00, /* ........ */
+/* --- new character '+' (43) starting at offset 0x008f --- */
+ /*008f:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0094:*/ 0x00, /* ........ */
+ /*0095:*/ 0x18, /* ...##... */
+ /*0096:*/ 0x18, /* ...##... */
+ /*0097:*/ 0x7e, /* .######. */
+ /*0098:*/ 0x18, /* ...##... */
+ /*0099:*/ 0x18, /* ...##... */
+ /*009a:*/ 0x00, /* ........ */
+ /*009b:*/ 0x00, /* ........ */
+/* --- new character ',' (44) starting at offset 0x009c --- */
+ /*009c:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00a1:*/ 0x00, /* ........ */
+ /*00a2:*/ 0x00, /* ........ */
+ /*00a3:*/ 0x00, /* ........ */
+ /*00a4:*/ 0x00, /* ........ */
+ /*00a5:*/ 0x00, /* ........ */
+ /*00a6:*/ 0x18, /* ...##... */
+ /*00a7:*/ 0x18, /* ...##... */
+ /*00a8:*/ 0x30, /* ..##.... */
+/* --- new character '-' (45) starting at offset 0x00a9 --- */
+ /*00a9:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00ae:*/ 0x00, /* ........ */
+ /*00af:*/ 0x00, /* ........ */
+ /*00b0:*/ 0x00, /* ........ */
+ /*00b1:*/ 0x7e, /* .######. */
+ /*00b2:*/ 0x00, /* ........ */
+ /*00b3:*/ 0x00, /* ........ */
+ /*00b4:*/ 0x00, /* ........ */
+ /*00b5:*/ 0x00, /* ........ */
+/* --- new character '.' (46) starting at offset 0x00b6 --- */
+ /*00b6:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00bb:*/ 0x00, /* ........ */
+ /*00bc:*/ 0x00, /* ........ */
+ /*00bd:*/ 0x00, /* ........ */
+ /*00be:*/ 0x00, /* ........ */
+ /*00bf:*/ 0x00, /* ........ */
+ /*00c0:*/ 0x18, /* ...##... */
+ /*00c1:*/ 0x18, /* ...##... */
+ /*00c2:*/ 0x00, /* ........ */
+/* --- new character '/' (47) starting at offset 0x00c3 --- */
+ /*00c3:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00c8:*/ 0x00, /* ........ */
+ /*00c9:*/ 0x03, /* ......## */
+ /*00ca:*/ 0x06, /* .....##. */
+ /*00cb:*/ 0x0c, /* ....##.. */
+ /*00cc:*/ 0x18, /* ...##... */
+ /*00cd:*/ 0x30, /* ..##.... */
+ /*00ce:*/ 0x60, /* .##..... */
+ /*00cf:*/ 0x00, /* ........ */
+/* --- new character '0' (48) starting at offset 0x00d0 --- */
+ /*00d0:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00d5:*/ 0x3c, /* ..####.. */
+ /*00d6:*/ 0x66, /* .##..##. */
+ /*00d7:*/ 0x6e, /* .##.###. */
+ /*00d8:*/ 0x76, /* .###.##. */
+ /*00d9:*/ 0x66, /* .##..##. */
+ /*00da:*/ 0x66, /* .##..##. */
+ /*00db:*/ 0x3c, /* ..####.. */
+ /*00dc:*/ 0x00, /* ........ */
+/* --- new character '1' (49) starting at offset 0x00dd --- */
+ /*00dd:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00e2:*/ 0x18, /* ...##... */
+ /*00e3:*/ 0x18, /* ...##... */
+ /*00e4:*/ 0x38, /* ..###... */
+ /*00e5:*/ 0x18, /* ...##... */
+ /*00e6:*/ 0x18, /* ...##... */
+ /*00e7:*/ 0x18, /* ...##... */
+ /*00e8:*/ 0x7e, /* .######. */
+ /*00e9:*/ 0x00, /* ........ */
+/* --- new character '2' (50) starting at offset 0x00ea --- */
+ /*00ea:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00ef:*/ 0x3c, /* ..####.. */
+ /*00f0:*/ 0x66, /* .##..##. */
+ /*00f1:*/ 0x06, /* .....##. */
+ /*00f2:*/ 0x0c, /* ....##.. */
+ /*00f3:*/ 0x30, /* ..##.... */
+ /*00f4:*/ 0x60, /* .##..... */
+ /*00f5:*/ 0x7e, /* .######. */
+ /*00f6:*/ 0x00, /* ........ */
+/* --- new character '3' (51) starting at offset 0x00f7 --- */
+ /*00f7:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00fc:*/ 0x3c, /* ..####.. */
+ /*00fd:*/ 0x66, /* .##..##. */
+ /*00fe:*/ 0x06, /* .....##. */
+ /*00ff:*/ 0x1c, /* ...###.. */
+ /*0100:*/ 0x06, /* .....##. */
+ /*0101:*/ 0x66, /* .##..##. */
+ /*0102:*/ 0x3c, /* ..####.. */
+ /*0103:*/ 0x00, /* ........ */
+/* --- new character '4' (52) starting at offset 0x0104 --- */
+ /*0104:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0109:*/ 0x06, /* .....##. */
+ /*010a:*/ 0x0e, /* ....###. */
+ /*010b:*/ 0x1e, /* ...####. */
+ /*010c:*/ 0x66, /* .##..##. */
+ /*010d:*/ 0x7f, /* .####### */
+ /*010e:*/ 0x06, /* .....##. */
+ /*010f:*/ 0x06, /* .....##. */
+ /*0110:*/ 0x00, /* ........ */
+/* --- new character '5' (53) starting at offset 0x0111 --- */
+ /*0111:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0116:*/ 0x7e, /* .######. */
+ /*0117:*/ 0x60, /* .##..... */
+ /*0118:*/ 0x7c, /* .#####.. */
+ /*0119:*/ 0x06, /* .....##. */
+ /*011a:*/ 0x06, /* .....##. */
+ /*011b:*/ 0x66, /* .##..##. */
+ /*011c:*/ 0x3c, /* ..####.. */
+ /*011d:*/ 0x00, /* ........ */
+/* --- new character '6' (54) starting at offset 0x011e --- */
+ /*011e:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0123:*/ 0x3c, /* ..####.. */
+ /*0124:*/ 0x66, /* .##..##. */
+ /*0125:*/ 0x60, /* .##..... */
+ /*0126:*/ 0x7c, /* .#####.. */
+ /*0127:*/ 0x66, /* .##..##. */
+ /*0128:*/ 0x66, /* .##..##. */
+ /*0129:*/ 0x3c, /* ..####.. */
+ /*012a:*/ 0x00, /* ........ */
+/* --- new character '7' (55) starting at offset 0x012b --- */
+ /*012b:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0130:*/ 0x7e, /* .######. */
+ /*0131:*/ 0x66, /* .##..##. */
+ /*0132:*/ 0x0c, /* ....##.. */
+ /*0133:*/ 0x18, /* ...##... */
+ /*0134:*/ 0x18, /* ...##... */
+ /*0135:*/ 0x18, /* ...##... */
+ /*0136:*/ 0x18, /* ...##... */
+ /*0137:*/ 0x00, /* ........ */
+/* --- new character '8' (56) starting at offset 0x0138 --- */
+ /*0138:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*013d:*/ 0x3c, /* ..####.. */
+ /*013e:*/ 0x66, /* .##..##. */
+ /*013f:*/ 0x66, /* .##..##. */
+ /*0140:*/ 0x3c, /* ..####.. */
+ /*0141:*/ 0x66, /* .##..##. */
+ /*0142:*/ 0x66, /* .##..##. */
+ /*0143:*/ 0x3c, /* ..####.. */
+ /*0144:*/ 0x00, /* ........ */
+/* --- new character '9' (57) starting at offset 0x0145 --- */
+ /*0145:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*014a:*/ 0x3c, /* ..####.. */
+ /*014b:*/ 0x66, /* .##..##. */
+ /*014c:*/ 0x66, /* .##..##. */
+ /*014d:*/ 0x3e, /* ..#####. */
+ /*014e:*/ 0x06, /* .....##. */
+ /*014f:*/ 0x66, /* .##..##. */
+ /*0150:*/ 0x3c, /* ..####.. */
+ /*0151:*/ 0x00, /* ........ */
+/* --- new character ':' (58) starting at offset 0x0152 --- */
+ /*0152:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0157:*/ 0x00, /* ........ */
+ /*0158:*/ 0x00, /* ........ */
+ /*0159:*/ 0x18, /* ...##... */
+ /*015a:*/ 0x00, /* ........ */
+ /*015b:*/ 0x00, /* ........ */
+ /*015c:*/ 0x18, /* ...##... */
+ /*015d:*/ 0x00, /* ........ */
+ /*015e:*/ 0x00, /* ........ */
+/* --- new character ';' (59) starting at offset 0x015f --- */
+ /*015f:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0164:*/ 0x00, /* ........ */
+ /*0165:*/ 0x00, /* ........ */
+ /*0166:*/ 0x18, /* ...##... */
+ /*0167:*/ 0x00, /* ........ */
+ /*0168:*/ 0x00, /* ........ */
+ /*0169:*/ 0x18, /* ...##... */
+ /*016a:*/ 0x18, /* ...##... */
+ /*016b:*/ 0x30, /* ..##.... */
+/* --- new character '<' (60) starting at offset 0x016c --- */
+ /*016c:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0171:*/ 0x0e, /* ....###. */
+ /*0172:*/ 0x18, /* ...##... */
+ /*0173:*/ 0x30, /* ..##.... */
+ /*0174:*/ 0x60, /* .##..... */
+ /*0175:*/ 0x30, /* ..##.... */
+ /*0176:*/ 0x18, /* ...##... */
+ /*0177:*/ 0x0e, /* ....###. */
+ /*0178:*/ 0x00, /* ........ */
+/* --- new character '=' (61) starting at offset 0x0179 --- */
+ /*0179:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*017e:*/ 0x00, /* ........ */
+ /*017f:*/ 0x00, /* ........ */
+ /*0180:*/ 0x7e, /* .######. */
+ /*0181:*/ 0x00, /* ........ */
+ /*0182:*/ 0x7e, /* .######. */
+ /*0183:*/ 0x00, /* ........ */
+ /*0184:*/ 0x00, /* ........ */
+ /*0185:*/ 0x00, /* ........ */
+/* --- new character '>' (62) starting at offset 0x0186 --- */
+ /*0186:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*018b:*/ 0x70, /* .###.... */
+ /*018c:*/ 0x18, /* ...##... */
+ /*018d:*/ 0x0c, /* ....##.. */
+ /*018e:*/ 0x06, /* .....##. */
+ /*018f:*/ 0x0c, /* ....##.. */
+ /*0190:*/ 0x18, /* ...##... */
+ /*0191:*/ 0x70, /* .###.... */
+ /*0192:*/ 0x00, /* ........ */
+/* --- new character '?' (63) starting at offset 0x0193 --- */
+ /*0193:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0198:*/ 0x3c, /* ..####.. */
+ /*0199:*/ 0x66, /* .##..##. */
+ /*019a:*/ 0x06, /* .....##. */
+ /*019b:*/ 0x0c, /* ....##.. */
+ /*019c:*/ 0x18, /* ...##... */
+ /*019d:*/ 0x00, /* ........ */
+ /*019e:*/ 0x18, /* ...##... */
+ /*019f:*/ 0x00, /* ........ */
+/* --- new character '@' (64) starting at offset 0x01a0 --- */
+ /*01a0:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01a5:*/ 0x3c, /* ..####.. */
+ /*01a6:*/ 0x66, /* .##..##. */
+ /*01a7:*/ 0x6e, /* .##.###. */
+ /*01a8:*/ 0x6e, /* .##.###. */
+ /*01a9:*/ 0x60, /* .##..... */
+ /*01aa:*/ 0x62, /* .##...#. */
+ /*01ab:*/ 0x3c, /* ..####.. */
+ /*01ac:*/ 0x00, /* ........ */
+/* --- new character 'A' (65) starting at offset 0x01ad --- */
+ /*01ad:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01b2:*/ 0x18, /* ...##... */
+ /*01b3:*/ 0x3c, /* ..####.. */
+ /*01b4:*/ 0x66, /* .##..##. */
+ /*01b5:*/ 0x7e, /* .######. */
+ /*01b6:*/ 0x66, /* .##..##. */
+ /*01b7:*/ 0x66, /* .##..##. */
+ /*01b8:*/ 0x66, /* .##..##. */
+ /*01b9:*/ 0x00, /* ........ */
+/* --- new character 'B' (66) starting at offset 0x01ba --- */
+ /*01ba:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01bf:*/ 0x7c, /* .#####.. */
+ /*01c0:*/ 0x66, /* .##..##. */
+ /*01c1:*/ 0x66, /* .##..##. */
+ /*01c2:*/ 0x7c, /* .#####.. */
+ /*01c3:*/ 0x66, /* .##..##. */
+ /*01c4:*/ 0x66, /* .##..##. */
+ /*01c5:*/ 0x7c, /* .#####.. */
+ /*01c6:*/ 0x00, /* ........ */
+/* --- new character 'C' (67) starting at offset 0x01c7 --- */
+ /*01c7:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01cc:*/ 0x3c, /* ..####.. */
+ /*01cd:*/ 0x66, /* .##..##. */
+ /*01ce:*/ 0x60, /* .##..... */
+ /*01cf:*/ 0x60, /* .##..... */
+ /*01d0:*/ 0x60, /* .##..... */
+ /*01d1:*/ 0x66, /* .##..##. */
+ /*01d2:*/ 0x3c, /* ..####.. */
+ /*01d3:*/ 0x00, /* ........ */
+/* --- new character 'D' (68) starting at offset 0x01d4 --- */
+ /*01d4:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01d9:*/ 0x78, /* .####... */
+ /*01da:*/ 0x6c, /* .##.##.. */
+ /*01db:*/ 0x66, /* .##..##. */
+ /*01dc:*/ 0x66, /* .##..##. */
+ /*01dd:*/ 0x66, /* .##..##. */
+ /*01de:*/ 0x6c, /* .##.##.. */
+ /*01df:*/ 0x78, /* .####... */
+ /*01e0:*/ 0x00, /* ........ */
+/* --- new character 'E' (69) starting at offset 0x01e1 --- */
+ /*01e1:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01e6:*/ 0x7e, /* .######. */
+ /*01e7:*/ 0x60, /* .##..... */
+ /*01e8:*/ 0x60, /* .##..... */
+ /*01e9:*/ 0x78, /* .####... */
+ /*01ea:*/ 0x60, /* .##..... */
+ /*01eb:*/ 0x60, /* .##..... */
+ /*01ec:*/ 0x7e, /* .######. */
+ /*01ed:*/ 0x00, /* ........ */
+/* --- new character 'F' (70) starting at offset 0x01ee --- */
+ /*01ee:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01f3:*/ 0x7e, /* .######. */
+ /*01f4:*/ 0x60, /* .##..... */
+ /*01f5:*/ 0x60, /* .##..... */
+ /*01f6:*/ 0x78, /* .####... */
+ /*01f7:*/ 0x60, /* .##..... */
+ /*01f8:*/ 0x60, /* .##..... */
+ /*01f9:*/ 0x60, /* .##..... */
+ /*01fa:*/ 0x00, /* ........ */
+/* --- new character 'G' (71) starting at offset 0x01fb --- */
+ /*01fb:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0200:*/ 0x3c, /* ..####.. */
+ /*0201:*/ 0x66, /* .##..##. */
+ /*0202:*/ 0x60, /* .##..... */
+ /*0203:*/ 0x6e, /* .##.###. */
+ /*0204:*/ 0x66, /* .##..##. */
+ /*0205:*/ 0x66, /* .##..##. */
+ /*0206:*/ 0x3c, /* ..####.. */
+ /*0207:*/ 0x00, /* ........ */
+/* --- new character 'H' (72) starting at offset 0x0208 --- */
+ /*0208:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*020d:*/ 0x66, /* .##..##. */
+ /*020e:*/ 0x66, /* .##..##. */
+ /*020f:*/ 0x66, /* .##..##. */
+ /*0210:*/ 0x7e, /* .######. */
+ /*0211:*/ 0x66, /* .##..##. */
+ /*0212:*/ 0x66, /* .##..##. */
+ /*0213:*/ 0x66, /* .##..##. */
+ /*0214:*/ 0x00, /* ........ */
+/* --- new character 'I' (73) starting at offset 0x0215 --- */
+ /*0215:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*021a:*/ 0x3c, /* ..####.. */
+ /*021b:*/ 0x18, /* ...##... */
+ /*021c:*/ 0x18, /* ...##... */
+ /*021d:*/ 0x18, /* ...##... */
+ /*021e:*/ 0x18, /* ...##... */
+ /*021f:*/ 0x18, /* ...##... */
+ /*0220:*/ 0x3c, /* ..####.. */
+ /*0221:*/ 0x00, /* ........ */
+/* --- new character 'J' (74) starting at offset 0x0222 --- */
+ /*0222:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0227:*/ 0x1e, /* ...####. */
+ /*0228:*/ 0x0c, /* ....##.. */
+ /*0229:*/ 0x0c, /* ....##.. */
+ /*022a:*/ 0x0c, /* ....##.. */
+ /*022b:*/ 0x0c, /* ....##.. */
+ /*022c:*/ 0x6c, /* .##.##.. */
+ /*022d:*/ 0x38, /* ..###... */
+ /*022e:*/ 0x00, /* ........ */
+/* --- new character 'K' (75) starting at offset 0x022f --- */
+ /*022f:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0234:*/ 0x66, /* .##..##. */
+ /*0235:*/ 0x6c, /* .##.##.. */
+ /*0236:*/ 0x78, /* .####... */
+ /*0237:*/ 0x70, /* .###.... */
+ /*0238:*/ 0x78, /* .####... */
+ /*0239:*/ 0x6c, /* .##.##.. */
+ /*023a:*/ 0x66, /* .##..##. */
+ /*023b:*/ 0x00, /* ........ */
+/* --- new character 'L' (76) starting at offset 0x023c --- */
+ /*023c:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0241:*/ 0x60, /* .##..... */
+ /*0242:*/ 0x60, /* .##..... */
+ /*0243:*/ 0x60, /* .##..... */
+ /*0244:*/ 0x60, /* .##..... */
+ /*0245:*/ 0x60, /* .##..... */
+ /*0246:*/ 0x60, /* .##..... */
+ /*0247:*/ 0x7e, /* .######. */
+ /*0248:*/ 0x00, /* ........ */
+/* --- new character 'M' (77) starting at offset 0x0249 --- */
+ /*0249:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*024e:*/ 0x63, /* .##...## */
+ /*024f:*/ 0x77, /* .###.### */
+ /*0250:*/ 0x7f, /* .####### */
+ /*0251:*/ 0x6b, /* .##.#.## */
+ /*0252:*/ 0x63, /* .##...## */
+ /*0253:*/ 0x63, /* .##...## */
+ /*0254:*/ 0x63, /* .##...## */
+ /*0255:*/ 0x00, /* ........ */
+/* --- new character 'N' (78) starting at offset 0x0256 --- */
+ /*0256:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*025b:*/ 0x66, /* .##..##. */
+ /*025c:*/ 0x76, /* .###.##. */
+ /*025d:*/ 0x7e, /* .######. */
+ /*025e:*/ 0x7e, /* .######. */
+ /*025f:*/ 0x6e, /* .##.###. */
+ /*0260:*/ 0x66, /* .##..##. */
+ /*0261:*/ 0x66, /* .##..##. */
+ /*0262:*/ 0x00, /* ........ */
+/* --- new character 'O' (79) starting at offset 0x0263 --- */
+ /*0263:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0268:*/ 0x3c, /* ..####.. */
+ /*0269:*/ 0x66, /* .##..##. */
+ /*026a:*/ 0x66, /* .##..##. */
+ /*026b:*/ 0x66, /* .##..##. */
+ /*026c:*/ 0x66, /* .##..##. */
+ /*026d:*/ 0x66, /* .##..##. */
+ /*026e:*/ 0x3c, /* ..####.. */
+ /*026f:*/ 0x00, /* ........ */
+/* --- new character 'P' (80) starting at offset 0x0270 --- */
+ /*0270:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0275:*/ 0x7c, /* .#####.. */
+ /*0276:*/ 0x66, /* .##..##. */
+ /*0277:*/ 0x66, /* .##..##. */
+ /*0278:*/ 0x7c, /* .#####.. */
+ /*0279:*/ 0x60, /* .##..... */
+ /*027a:*/ 0x60, /* .##..... */
+ /*027b:*/ 0x60, /* .##..... */
+ /*027c:*/ 0x00, /* ........ */
+/* --- new character 'Q' (81) starting at offset 0x027d --- */
+ /*027d:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0282:*/ 0x3c, /* ..####.. */
+ /*0283:*/ 0x66, /* .##..##. */
+ /*0284:*/ 0x66, /* .##..##. */
+ /*0285:*/ 0x66, /* .##..##. */
+ /*0286:*/ 0x66, /* .##..##. */
+ /*0287:*/ 0x3c, /* ..####.. */
+ /*0288:*/ 0x0e, /* ....###. */
+ /*0289:*/ 0x00, /* ........ */
+/* --- new character 'R' (82) starting at offset 0x028a --- */
+ /*028a:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*028f:*/ 0x7c, /* .#####.. */
+ /*0290:*/ 0x66, /* .##..##. */
+ /*0291:*/ 0x66, /* .##..##. */
+ /*0292:*/ 0x7c, /* .#####.. */
+ /*0293:*/ 0x78, /* .####... */
+ /*0294:*/ 0x6c, /* .##.##.. */
+ /*0295:*/ 0x66, /* .##..##. */
+ /*0296:*/ 0x00, /* ........ */
+/* --- new character 'S' (83) starting at offset 0x0297 --- */
+ /*0297:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*029c:*/ 0x3c, /* ..####.. */
+ /*029d:*/ 0x66, /* .##..##. */
+ /*029e:*/ 0x60, /* .##..... */
+ /*029f:*/ 0x3c, /* ..####.. */
+ /*02a0:*/ 0x06, /* .....##. */
+ /*02a1:*/ 0x66, /* .##..##. */
+ /*02a2:*/ 0x3c, /* ..####.. */
+ /*02a3:*/ 0x00, /* ........ */
+/* --- new character 'T' (84) starting at offset 0x02a4 --- */
+ /*02a4:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02a9:*/ 0x7e, /* .######. */
+ /*02aa:*/ 0x18, /* ...##... */
+ /*02ab:*/ 0x18, /* ...##... */
+ /*02ac:*/ 0x18, /* ...##... */
+ /*02ad:*/ 0x18, /* ...##... */
+ /*02ae:*/ 0x18, /* ...##... */
+ /*02af:*/ 0x18, /* ...##... */
+ /*02b0:*/ 0x00, /* ........ */
+/* --- new character 'U' (85) starting at offset 0x02b1 --- */
+ /*02b1:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02b6:*/ 0x66, /* .##..##. */
+ /*02b7:*/ 0x66, /* .##..##. */
+ /*02b8:*/ 0x66, /* .##..##. */
+ /*02b9:*/ 0x66, /* .##..##. */
+ /*02ba:*/ 0x66, /* .##..##. */
+ /*02bb:*/ 0x66, /* .##..##. */
+ /*02bc:*/ 0x3c, /* ..####.. */
+ /*02bd:*/ 0x00, /* ........ */
+/* --- new character 'V' (86) starting at offset 0x02be --- */
+ /*02be:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02c3:*/ 0x66, /* .##..##. */
+ /*02c4:*/ 0x66, /* .##..##. */
+ /*02c5:*/ 0x66, /* .##..##. */
+ /*02c6:*/ 0x66, /* .##..##. */
+ /*02c7:*/ 0x66, /* .##..##. */
+ /*02c8:*/ 0x3c, /* ..####.. */
+ /*02c9:*/ 0x18, /* ...##... */
+ /*02ca:*/ 0x00, /* ........ */
+/* --- new character 'W' (87) starting at offset 0x02cb --- */
+ /*02cb:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02d0:*/ 0x63, /* .##...## */
+ /*02d1:*/ 0x63, /* .##...## */
+ /*02d2:*/ 0x63, /* .##...## */
+ /*02d3:*/ 0x6b, /* .##.#.## */
+ /*02d4:*/ 0x7f, /* .####### */
+ /*02d5:*/ 0x77, /* .###.### */
+ /*02d6:*/ 0x63, /* .##...## */
+ /*02d7:*/ 0x00, /* ........ */
+/* --- new character 'X' (88) starting at offset 0x02d8 --- */
+ /*02d8:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02dd:*/ 0x66, /* .##..##. */
+ /*02de:*/ 0x66, /* .##..##. */
+ /*02df:*/ 0x3c, /* ..####.. */
+ /*02e0:*/ 0x18, /* ...##... */
+ /*02e1:*/ 0x3c, /* ..####.. */
+ /*02e2:*/ 0x66, /* .##..##. */
+ /*02e3:*/ 0x66, /* .##..##. */
+ /*02e4:*/ 0x00, /* ........ */
+/* --- new character 'Y' (89) starting at offset 0x02e5 --- */
+ /*02e5:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02ea:*/ 0x66, /* .##..##. */
+ /*02eb:*/ 0x66, /* .##..##. */
+ /*02ec:*/ 0x66, /* .##..##. */
+ /*02ed:*/ 0x3c, /* ..####.. */
+ /*02ee:*/ 0x18, /* ...##... */
+ /*02ef:*/ 0x18, /* ...##... */
+ /*02f0:*/ 0x18, /* ...##... */
+ /*02f1:*/ 0x00, /* ........ */
+/* --- new character 'Z' (90) starting at offset 0x02f2 --- */
+ /*02f2:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02f7:*/ 0x7e, /* .######. */
+ /*02f8:*/ 0x06, /* .....##. */
+ /*02f9:*/ 0x0c, /* ....##.. */
+ /*02fa:*/ 0x18, /* ...##... */
+ /*02fb:*/ 0x30, /* ..##.... */
+ /*02fc:*/ 0x60, /* .##..... */
+ /*02fd:*/ 0x7e, /* .######. */
+ /*02fe:*/ 0x00, /* ........ */
+/* --- new character '[' (91) starting at offset 0x02ff --- */
+ /*02ff:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0304:*/ 0x3c, /* ..####.. */
+ /*0305:*/ 0x30, /* ..##.... */
+ /*0306:*/ 0x30, /* ..##.... */
+ /*0307:*/ 0x30, /* ..##.... */
+ /*0308:*/ 0x30, /* ..##.... */
+ /*0309:*/ 0x30, /* ..##.... */
+ /*030a:*/ 0x3c, /* ..####.. */
+ /*030b:*/ 0x00, /* ........ */
+/* --- new character '\' (92) starting at offset 0x030c --- */
+ /*030c:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0311:*/ 0x00, /* ........ */
+ /*0312:*/ 0xc0, /* ##...... */
+ /*0313:*/ 0x60, /* .##..... */
+ /*0314:*/ 0x30, /* ..##.... */
+ /*0315:*/ 0x18, /* ...##... */
+ /*0316:*/ 0x0c, /* ....##.. */
+ /*0317:*/ 0x06, /* .....##. */
+ /*0318:*/ 0x00, /* ........ */
+/* --- new character ']' (93) starting at offset 0x0319 --- */
+ /*0319:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*031e:*/ 0x3c, /* ..####.. */
+ /*031f:*/ 0x0c, /* ....##.. */
+ /*0320:*/ 0x0c, /* ....##.. */
+ /*0321:*/ 0x0c, /* ....##.. */
+ /*0322:*/ 0x0c, /* ....##.. */
+ /*0323:*/ 0x0c, /* ....##.. */
+ /*0324:*/ 0x3c, /* ..####.. */
+ /*0325:*/ 0x00, /* ........ */
+/* --- new character '^' (94) starting at offset 0x0326 --- */
+ /*0326:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*032b:*/ 0x18, /* ...##... */
+ /*032c:*/ 0x3c, /* ..####.. */
+ /*032d:*/ 0x66, /* .##..##. */
+ /*032e:*/ 0x00, /* ........ */
+ /*032f:*/ 0x00, /* ........ */
+ /*0330:*/ 0x00, /* ........ */
+ /*0331:*/ 0x00, /* ........ */
+ /*0332:*/ 0x00, /* ........ */
+/* --- new character '_' (95) starting at offset 0x0333 --- */
+ /*0333:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0338:*/ 0x00, /* ........ */
+ /*0339:*/ 0x00, /* ........ */
+ /*033a:*/ 0x00, /* ........ */
+ /*033b:*/ 0x00, /* ........ */
+ /*033c:*/ 0x00, /* ........ */
+ /*033d:*/ 0x00, /* ........ */
+ /*033e:*/ 0x00, /* ........ */
+ /*033f:*/ 0xff, /* ######## */
+/* --- new character '`' (96) starting at offset 0x0340 --- */
+ /*0340:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0345:*/ 0x60, /* .##..... */
+ /*0346:*/ 0x30, /* ..##.... */
+ /*0347:*/ 0x18, /* ...##... */
+ /*0348:*/ 0x00, /* ........ */
+ /*0349:*/ 0x00, /* ........ */
+ /*034a:*/ 0x00, /* ........ */
+ /*034b:*/ 0x00, /* ........ */
+ /*034c:*/ 0x00, /* ........ */
+/* --- new character 'a' (97) starting at offset 0x034d --- */
+ /*034d:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0352:*/ 0x00, /* ........ */
+ /*0353:*/ 0x00, /* ........ */
+ /*0354:*/ 0x3c, /* ..####.. */
+ /*0355:*/ 0x06, /* .....##. */
+ /*0356:*/ 0x3e, /* ..#####. */
+ /*0357:*/ 0x66, /* .##..##. */
+ /*0358:*/ 0x3e, /* ..#####. */
+ /*0359:*/ 0x00, /* ........ */
+/* --- new character 'b' (98) starting at offset 0x035a --- */
+ /*035a:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*035f:*/ 0x00, /* ........ */
+ /*0360:*/ 0x60, /* .##..... */
+ /*0361:*/ 0x60, /* .##..... */
+ /*0362:*/ 0x7c, /* .#####.. */
+ /*0363:*/ 0x66, /* .##..##. */
+ /*0364:*/ 0x66, /* .##..##. */
+ /*0365:*/ 0x7c, /* .#####.. */
+ /*0366:*/ 0x00, /* ........ */
+/* --- new character 'c' (99) starting at offset 0x0367 --- */
+ /*0367:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*036c:*/ 0x00, /* ........ */
+ /*036d:*/ 0x00, /* ........ */
+ /*036e:*/ 0x3c, /* ..####.. */
+ /*036f:*/ 0x60, /* .##..... */
+ /*0370:*/ 0x60, /* .##..... */
+ /*0371:*/ 0x60, /* .##..... */
+ /*0372:*/ 0x3c, /* ..####.. */
+ /*0373:*/ 0x00, /* ........ */
+/* --- new character 'd' (100) starting at offset 0x0374 --- */
+ /*0374:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0379:*/ 0x00, /* ........ */
+ /*037a:*/ 0x06, /* .....##. */
+ /*037b:*/ 0x06, /* .....##. */
+ /*037c:*/ 0x3e, /* ..#####. */
+ /*037d:*/ 0x66, /* .##..##. */
+ /*037e:*/ 0x66, /* .##..##. */
+ /*037f:*/ 0x3e, /* ..#####. */
+ /*0380:*/ 0x00, /* ........ */
+/* --- new character 'e' (101) starting at offset 0x0381 --- */
+ /*0381:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0386:*/ 0x00, /* ........ */
+ /*0387:*/ 0x00, /* ........ */
+ /*0388:*/ 0x3c, /* ..####.. */
+ /*0389:*/ 0x66, /* .##..##. */
+ /*038a:*/ 0x7e, /* .######. */
+ /*038b:*/ 0x60, /* .##..... */
+ /*038c:*/ 0x3c, /* ..####.. */
+ /*038d:*/ 0x00, /* ........ */
+/* --- new character 'f' (102) starting at offset 0x038e --- */
+ /*038e:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0393:*/ 0x00, /* ........ */
+ /*0394:*/ 0x0e, /* ....###. */
+ /*0395:*/ 0x18, /* ...##... */
+ /*0396:*/ 0x3e, /* ..#####. */
+ /*0397:*/ 0x18, /* ...##... */
+ /*0398:*/ 0x18, /* ...##... */
+ /*0399:*/ 0x18, /* ...##... */
+ /*039a:*/ 0x00, /* ........ */
+/* --- new character 'g' (103) starting at offset 0x039b --- */
+ /*039b:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03a0:*/ 0x00, /* ........ */
+ /*03a1:*/ 0x00, /* ........ */
+ /*03a2:*/ 0x3e, /* ..#####. */
+ /*03a3:*/ 0x66, /* .##..##. */
+ /*03a4:*/ 0x66, /* .##..##. */
+ /*03a5:*/ 0x3e, /* ..#####. */
+ /*03a6:*/ 0x06, /* .....##. */
+ /*03a7:*/ 0x7c, /* .#####.. */
+/* --- new character 'h' (104) starting at offset 0x03a8 --- */
+ /*03a8:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03ad:*/ 0x00, /* ........ */
+ /*03ae:*/ 0x60, /* .##..... */
+ /*03af:*/ 0x60, /* .##..... */
+ /*03b0:*/ 0x7c, /* .#####.. */
+ /*03b1:*/ 0x66, /* .##..##. */
+ /*03b2:*/ 0x66, /* .##..##. */
+ /*03b3:*/ 0x66, /* .##..##. */
+ /*03b4:*/ 0x00, /* ........ */
+/* --- new character 'i' (105) starting at offset 0x03b5 --- */
+ /*03b5:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03ba:*/ 0x00, /* ........ */
+ /*03bb:*/ 0x18, /* ...##... */
+ /*03bc:*/ 0x00, /* ........ */
+ /*03bd:*/ 0x38, /* ..###... */
+ /*03be:*/ 0x18, /* ...##... */
+ /*03bf:*/ 0x18, /* ...##... */
+ /*03c0:*/ 0x3c, /* ..####.. */
+ /*03c1:*/ 0x00, /* ........ */
+/* --- new character 'j' (106) starting at offset 0x03c2 --- */
+ /*03c2:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03c7:*/ 0x00, /* ........ */
+ /*03c8:*/ 0x06, /* .....##. */
+ /*03c9:*/ 0x00, /* ........ */
+ /*03ca:*/ 0x06, /* .....##. */
+ /*03cb:*/ 0x06, /* .....##. */
+ /*03cc:*/ 0x06, /* .....##. */
+ /*03cd:*/ 0x06, /* .....##. */
+ /*03ce:*/ 0x3c, /* ..####.. */
+/* --- new character 'k' (107) starting at offset 0x03cf --- */
+ /*03cf:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03d4:*/ 0x00, /* ........ */
+ /*03d5:*/ 0x60, /* .##..... */
+ /*03d6:*/ 0x60, /* .##..... */
+ /*03d7:*/ 0x6c, /* .##.##.. */
+ /*03d8:*/ 0x78, /* .####... */
+ /*03d9:*/ 0x6c, /* .##.##.. */
+ /*03da:*/ 0x66, /* .##..##. */
+ /*03db:*/ 0x00, /* ........ */
+/* --- new character 'l' (108) starting at offset 0x03dc --- */
+ /*03dc:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03e1:*/ 0x00, /* ........ */
+ /*03e2:*/ 0x38, /* ..###... */
+ /*03e3:*/ 0x18, /* ...##... */
+ /*03e4:*/ 0x18, /* ...##... */
+ /*03e5:*/ 0x18, /* ...##... */
+ /*03e6:*/ 0x18, /* ...##... */
+ /*03e7:*/ 0x3c, /* ..####.. */
+ /*03e8:*/ 0x00, /* ........ */
+/* --- new character 'm' (109) starting at offset 0x03e9 --- */
+ /*03e9:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03ee:*/ 0x00, /* ........ */
+ /*03ef:*/ 0x00, /* ........ */
+ /*03f0:*/ 0x66, /* .##..##. */
+ /*03f1:*/ 0x7f, /* .####### */
+ /*03f2:*/ 0x7f, /* .####### */
+ /*03f3:*/ 0x6b, /* .##.#.## */
+ /*03f4:*/ 0x63, /* .##...## */
+ /*03f5:*/ 0x00, /* ........ */
+/* --- new character 'n' (110) starting at offset 0x03f6 --- */
+ /*03f6:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03fb:*/ 0x00, /* ........ */
+ /*03fc:*/ 0x00, /* ........ */
+ /*03fd:*/ 0x7c, /* .#####.. */
+ /*03fe:*/ 0x66, /* .##..##. */
+ /*03ff:*/ 0x66, /* .##..##. */
+ /*0400:*/ 0x66, /* .##..##. */
+ /*0401:*/ 0x66, /* .##..##. */
+ /*0402:*/ 0x00, /* ........ */
+/* --- new character 'o' (111) starting at offset 0x0403 --- */
+ /*0403:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0408:*/ 0x00, /* ........ */
+ /*0409:*/ 0x00, /* ........ */
+ /*040a:*/ 0x3c, /* ..####.. */
+ /*040b:*/ 0x66, /* .##..##. */
+ /*040c:*/ 0x66, /* .##..##. */
+ /*040d:*/ 0x66, /* .##..##. */
+ /*040e:*/ 0x3c, /* ..####.. */
+ /*040f:*/ 0x00, /* ........ */
+/* --- new character 'p' (112) starting at offset 0x0410 --- */
+ /*0410:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0415:*/ 0x00, /* ........ */
+ /*0416:*/ 0x00, /* ........ */
+ /*0417:*/ 0x7c, /* .#####.. */
+ /*0418:*/ 0x66, /* .##..##. */
+ /*0419:*/ 0x66, /* .##..##. */
+ /*041a:*/ 0x7c, /* .#####.. */
+ /*041b:*/ 0x60, /* .##..... */
+ /*041c:*/ 0x60, /* .##..... */
+/* --- new character 'q' (113) starting at offset 0x041d --- */
+ /*041d:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0422:*/ 0x00, /* ........ */
+ /*0423:*/ 0x00, /* ........ */
+ /*0424:*/ 0x3e, /* ..#####. */
+ /*0425:*/ 0x66, /* .##..##. */
+ /*0426:*/ 0x66, /* .##..##. */
+ /*0427:*/ 0x3e, /* ..#####. */
+ /*0428:*/ 0x06, /* .....##. */
+ /*0429:*/ 0x06, /* .....##. */
+/* --- new character 'r' (114) starting at offset 0x042a --- */
+ /*042a:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*042f:*/ 0x00, /* ........ */
+ /*0430:*/ 0x00, /* ........ */
+ /*0431:*/ 0x7c, /* .#####.. */
+ /*0432:*/ 0x66, /* .##..##. */
+ /*0433:*/ 0x60, /* .##..... */
+ /*0434:*/ 0x60, /* .##..... */
+ /*0435:*/ 0x60, /* .##..... */
+ /*0436:*/ 0x00, /* ........ */
+/* --- new character 's' (115) starting at offset 0x0437 --- */
+ /*0437:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*043c:*/ 0x00, /* ........ */
+ /*043d:*/ 0x00, /* ........ */
+ /*043e:*/ 0x3e, /* ..#####. */
+ /*043f:*/ 0x60, /* .##..... */
+ /*0440:*/ 0x3c, /* ..####.. */
+ /*0441:*/ 0x06, /* .....##. */
+ /*0442:*/ 0x7c, /* .#####.. */
+ /*0443:*/ 0x00, /* ........ */
+/* --- new character 't' (116) starting at offset 0x0444 --- */
+ /*0444:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0449:*/ 0x00, /* ........ */
+ /*044a:*/ 0x18, /* ...##... */
+ /*044b:*/ 0x7e, /* .######. */
+ /*044c:*/ 0x18, /* ...##... */
+ /*044d:*/ 0x18, /* ...##... */
+ /*044e:*/ 0x18, /* ...##... */
+ /*044f:*/ 0x0e, /* ....###. */
+ /*0450:*/ 0x00, /* ........ */
+/* --- new character 'u' (117) starting at offset 0x0451 --- */
+ /*0451:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0456:*/ 0x00, /* ........ */
+ /*0457:*/ 0x00, /* ........ */
+ /*0458:*/ 0x66, /* .##..##. */
+ /*0459:*/ 0x66, /* .##..##. */
+ /*045a:*/ 0x66, /* .##..##. */
+ /*045b:*/ 0x66, /* .##..##. */
+ /*045c:*/ 0x3e, /* ..#####. */
+ /*045d:*/ 0x00, /* ........ */
+/* --- new character 'v' (118) starting at offset 0x045e --- */
+ /*045e:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0463:*/ 0x00, /* ........ */
+ /*0464:*/ 0x00, /* ........ */
+ /*0465:*/ 0x66, /* .##..##. */
+ /*0466:*/ 0x66, /* .##..##. */
+ /*0467:*/ 0x66, /* .##..##. */
+ /*0468:*/ 0x3c, /* ..####.. */
+ /*0469:*/ 0x18, /* ...##... */
+ /*046a:*/ 0x00, /* ........ */
+/* --- new character 'w' (119) starting at offset 0x046b --- */
+ /*046b:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0470:*/ 0x00, /* ........ */
+ /*0471:*/ 0x00, /* ........ */
+ /*0472:*/ 0x63, /* .##...## */
+ /*0473:*/ 0x6b, /* .##.#.## */
+ /*0474:*/ 0x7f, /* .####### */
+ /*0475:*/ 0x3e, /* ..#####. */
+ /*0476:*/ 0x36, /* ..##.##. */
+ /*0477:*/ 0x00, /* ........ */
+/* --- new character 'x' (120) starting at offset 0x0478 --- */
+ /*0478:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*047d:*/ 0x00, /* ........ */
+ /*047e:*/ 0x00, /* ........ */
+ /*047f:*/ 0x66, /* .##..##. */
+ /*0480:*/ 0x3c, /* ..####.. */
+ /*0481:*/ 0x18, /* ...##... */
+ /*0482:*/ 0x3c, /* ..####.. */
+ /*0483:*/ 0x66, /* .##..##. */
+ /*0484:*/ 0x00, /* ........ */
+/* --- new character 'y' (121) starting at offset 0x0485 --- */
+ /*0485:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*048a:*/ 0x00, /* ........ */
+ /*048b:*/ 0x00, /* ........ */
+ /*048c:*/ 0x66, /* .##..##. */
+ /*048d:*/ 0x66, /* .##..##. */
+ /*048e:*/ 0x66, /* .##..##. */
+ /*048f:*/ 0x3e, /* ..#####. */
+ /*0490:*/ 0x0c, /* ....##.. */
+ /*0491:*/ 0x78, /* .####... */
+/* --- new character 'z' (122) starting at offset 0x0492 --- */
+ /*0492:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0497:*/ 0x00, /* ........ */
+ /*0498:*/ 0x00, /* ........ */
+ /*0499:*/ 0x7e, /* .######. */
+ /*049a:*/ 0x0c, /* ....##.. */
+ /*049b:*/ 0x18, /* ...##... */
+ /*049c:*/ 0x30, /* ..##.... */
+ /*049d:*/ 0x7e, /* .######. */
+ /*049e:*/ 0x00, /* ........ */
+/* --- new character '{' (123) starting at offset 0x049f --- */
+ /*049f:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*04a4:*/ 0x1c, /* ...###.. */
+ /*04a5:*/ 0x30, /* ..##.... */
+ /*04a6:*/ 0x30, /* ..##.... */
+ /*04a7:*/ 0x60, /* .##..... */
+ /*04a8:*/ 0x30, /* ..##.... */
+ /*04a9:*/ 0x30, /* ..##.... */
+ /*04aa:*/ 0x1c, /* ...###.. */
+ /*04ab:*/ 0x00, /* ........ */
+/* --- new character '|' (124) starting at offset 0x04ac --- */
+ /*04ac:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*04b1:*/ 0x18, /* ...##... */
+ /*04b2:*/ 0x18, /* ...##... */
+ /*04b3:*/ 0x18, /* ...##... */
+ /*04b4:*/ 0x18, /* ...##... */
+ /*04b5:*/ 0x18, /* ...##... */
+ /*04b6:*/ 0x18, /* ...##... */
+ /*04b7:*/ 0x18, /* ...##... */
+ /*04b8:*/ 0x00, /* ........ */
+/* --- new character '}' (125) starting at offset 0x04b9 --- */
+ /*04b9:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*04be:*/ 0x38, /* ..###... */
+ /*04bf:*/ 0x0c, /* ....##.. */
+ /*04c0:*/ 0x0c, /* ....##.. */
+ /*04c1:*/ 0x06, /* .....##. */
+ /*04c2:*/ 0x0c, /* ....##.. */
+ /*04c3:*/ 0x0c, /* ....##.. */
+ /*04c4:*/ 0x38, /* ..###... */
+ /*04c5:*/ 0x00, /* ........ */
+/* --- new character '~' (126) starting at offset 0x04c6 --- */
+ /*04c6:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*04cb:*/ 0x33, /* ..##..## */
+ /*04cc:*/ 0x7e, /* .######. */
+ /*04cd:*/ 0xcc, /* ##..##.. */
+ /*04ce:*/ 0x00, /* ........ */
+ /*04cf:*/ 0x00, /* ........ */
+ /*04d0:*/ 0x00, /* ........ */
+ /*04d1:*/ 0x00, /* ........ */
+ /*04d2:*/ 0x00, /* ........ */
+/* --- new character '' (127) starting at offset 0x04d3 --- */
+ /*04d3:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*04d8:*/ 0x00, /* ........ */
+ /*04d9:*/ 0x08, /* ....#... */
+ /*04da:*/ 0x0c, /* ....##.. */
+ /*04db:*/ 0xfe, /* #######. */
+ /*04dc:*/ 0xfe, /* #######. */
+ /*04dd:*/ 0x0c, /* ....##.. */
+ /*04de:*/ 0x08, /* ....#... */
+ /*04df:*/ 0x00, /* ........ */
+};
+static const uint16_t font_c64_offsets[] = {
+ 0x0000 /* ' ' */,
+ 0x000d /* '!' */,
+ 0x001a /* '"' */,
+ 0x0027 /* '#' */,
+ 0x0034 /* '$' */,
+ 0x0041 /* '%' */,
+ 0x004e /* '&' */,
+ 0x005b /* ''' */,
+ 0x0068 /* '(' */,
+ 0x0075 /* ')' */,
+ 0x0082 /* '*' */,
+ 0x008f /* '+' */,
+ 0x009c /* ',' */,
+ 0x00a9 /* '-' */,
+ 0x00b6 /* '.' */,
+ 0x00c3 /* '/' */,
+ 0x00d0 /* '0' */,
+ 0x00dd /* '1' */,
+ 0x00ea /* '2' */,
+ 0x00f7 /* '3' */,
+ 0x0104 /* '4' */,
+ 0x0111 /* '5' */,
+ 0x011e /* '6' */,
+ 0x012b /* '7' */,
+ 0x0138 /* '8' */,
+ 0x0145 /* '9' */,
+ 0x0152 /* ':' */,
+ 0x015f /* ';' */,
+ 0x016c /* '<' */,
+ 0x0179 /* '=' */,
+ 0x0186 /* '>' */,
+ 0x0193 /* '?' */,
+ 0x01a0 /* '@' */,
+ 0x01ad /* 'A' */,
+ 0x01ba /* 'B' */,
+ 0x01c7 /* 'C' */,
+ 0x01d4 /* 'D' */,
+ 0x01e1 /* 'E' */,
+ 0x01ee /* 'F' */,
+ 0x01fb /* 'G' */,
+ 0x0208 /* 'H' */,
+ 0x0215 /* 'I' */,
+ 0x0222 /* 'J' */,
+ 0x022f /* 'K' */,
+ 0x023c /* 'L' */,
+ 0x0249 /* 'M' */,
+ 0x0256 /* 'N' */,
+ 0x0263 /* 'O' */,
+ 0x0270 /* 'P' */,
+ 0x027d /* 'Q' */,
+ 0x028a /* 'R' */,
+ 0x0297 /* 'S' */,
+ 0x02a4 /* 'T' */,
+ 0x02b1 /* 'U' */,
+ 0x02be /* 'V' */,
+ 0x02cb /* 'W' */,
+ 0x02d8 /* 'X' */,
+ 0x02e5 /* 'Y' */,
+ 0x02f2 /* 'Z' */,
+ 0x02ff /* '[' */,
+ 0x030c /* '\' */,
+ 0x0319 /* ']' */,
+ 0x0326 /* '^' */,
+ 0x0333 /* '_' */,
+ 0x0340 /* '`' */,
+ 0x034d /* 'a' */,
+ 0x035a /* 'b' */,
+ 0x0367 /* 'c' */,
+ 0x0374 /* 'd' */,
+ 0x0381 /* 'e' */,
+ 0x038e /* 'f' */,
+ 0x039b /* 'g' */,
+ 0x03a8 /* 'h' */,
+ 0x03b5 /* 'i' */,
+ 0x03c2 /* 'j' */,
+ 0x03cf /* 'k' */,
+ 0x03dc /* 'l' */,
+ 0x03e9 /* 'm' */,
+ 0x03f6 /* 'n' */,
+ 0x0403 /* 'o' */,
+ 0x0410 /* 'p' */,
+ 0x041d /* 'q' */,
+ 0x042a /* 'r' */,
+ 0x0437 /* 's' */,
+ 0x0444 /* 't' */,
+ 0x0451 /* 'u' */,
+ 0x045e /* 'v' */,
+ 0x046b /* 'w' */,
+ 0x0478 /* 'x' */,
+ 0x0485 /* 'y' */,
+ 0x0492 /* 'z' */,
+ 0x049f /* '{' */,
+ 0x04ac /* '|' */,
+ 0x04b9 /* '}' */,
+ 0x04c6 /* '~' */,
+ 0x04d3 /* '' */,
+};
+const struct fb_font font_c64 = {
+ .height = 8,
+ .ascent = 8,
+ .firstchar = 32, /* space */
+ .lastchar = 127, /* ? */
+ .chardata = font_c64_data,
+ .charoffs = font_c64_offsets,
+};
diff --git a/src/target/firmware/fb/fb_bw8.c b/src/target/firmware/fb/fb_bw8.c
new file mode 100644
index 00000000..ffb59d81
--- /dev/null
+++ b/src/target/firmware/fb/fb_bw8.c
@@ -0,0 +1,311 @@
+/* utility functions for a black-and-white framebuffer organized
+ as 8-vertically-stacked-pixels per byte. This matches the
+ ST7558 LC Display Controller used on the Motorola C123 */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <fb/fb_bw8.h>
+
+#include <stdio.h> // debugging
+
+void fb_bw8_clear(){
+ int i,n;
+
+ /* bytes to clear */
+ n = (framebuffer->height+7)/8 * framebuffer->width;
+ for(i=0;i<n;i++)
+ fb_bw8->mem[i]=0;
+
+ /* mark everything as dirty */
+ fb_bw8->damage_x1 = 0;
+ fb_bw8->damage_x2 = framebuffer->width;
+ fb_bw8->damage_y1 = 0;
+ fb_bw8->damage_y2 = framebuffer->height;
+}
+
+/* update damage rectangle to include the area
+ x1,y1 (upper left) to x2,y2 (lower right)
+ Note that all pixels *including* x1y2 and x2y2 are
+ marked as dirty */
+static void fb_bw8_update_damage(
+ uint16_t x1,uint16_t y1, /* left upper corner (inclusive) */
+ uint16_t x2,uint16_t y2 /* right lower corner (inclusive) */
+){
+ fb_sanitize_box(&x1,&y1,&x2,&y2);
+
+ x2++; /* see definition of fb_bw8->damage_x2/y2 */
+ y2++;
+
+ /* maybe currently everything is clean? */
+ if(fb_bw8->damage_x1 == fb_bw8->damage_x2 ||
+ fb_bw8->damage_y1 == fb_bw8->damage_y2){
+ fb_bw8->damage_x1 = x1;
+ fb_bw8->damage_y1 = y1;
+ fb_bw8->damage_x2 = x2;
+ fb_bw8->damage_y2 = y2;
+/*
+ printf("%s: was clean! damage now %d %d %d %d\n",
+ __FUNCTION__,fb_bw8->damage_x1,fb_bw8->damage_y1,
+ fb_bw8->damage_x2,fb_bw8->damage_y2);
+*/
+ return;
+ }
+
+ /* grow damage box */
+ if(x1 < fb_bw8->damage_x1)
+ fb_bw8->damage_x1 = x1;
+ if(y1 < fb_bw8->damage_y1)
+ fb_bw8->damage_y1 = y1;
+ if(x2 > fb_bw8->damage_x2)
+ fb_bw8->damage_x2 = x2;
+ if(y2 > fb_bw8->damage_y2)
+ fb_bw8->damage_y2 = y2;
+#if 0
+ printf("%s: damage now %d %d %d %d\n",
+ __FUNCTION__,fb_bw8->damage_x1,fb_bw8->damage_y1,
+ fb_bw8->damage_x2,fb_bw8->damage_y2);
+#endif
+}
+
+static void fb_bw8_line(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2){
+ fb_sanitize_box(&x1,&y1,&x2,&y2);
+ /* FIXME : this is currently unimplemented! */
+}
+
+void fb_bw8_lineto(uint16_t x,uint16_t y){
+ fb_bw8_line(framebuffer->cursor_x,framebuffer->cursor_y,x,y);
+ framebuffer->cursor_x = x;
+ framebuffer->cursor_y = y;
+}
+
+/* depending on color set (add to or_mask) or clear
+ (remove from and_mask) bit number bitnum */
+static void set_pixel(uint8_t *and_mask,
+ uint8_t *or_mask,
+ int bitnum,
+ uint32_t color
+){
+ if(color == FB_COLOR_TRANSP)
+ return;
+ if(color == FB_COLOR_WHITE)
+ *and_mask &= ~(1<<bitnum);
+ else
+ *or_mask |= 1<<bitnum;
+}
+
+static void set_fg_pixel(uint8_t *and_mask,uint8_t *or_mask,int bitnum){
+ set_pixel(and_mask,or_mask,bitnum,framebuffer->fg_color);
+}
+
+static void set_bg_pixel(uint8_t *and_mask,uint8_t *or_mask,int bitnum){
+ set_pixel(and_mask,or_mask,bitnum,framebuffer->bg_color);
+}
+
+static void fb_bw8_box(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
+{
+ uint16_t y,w;
+ uint8_t *p;
+
+ uint8_t and_mask,or_mask; // filling
+ uint8_t and_mask_side,or_mask_side; // left and right side
+
+ fb_sanitize_box(&x1,&y1,&x2,&y2);
+ fb_bw8_update_damage(x1,y1,x2,y2);
+
+ for(y=y1&0xfff8;y<=y2;y+=8){
+ /* don't clear any pixels (white) */
+ and_mask = and_mask_side = 0xff;
+ or_mask = or_mask_side = 0;
+
+ for(w=0;w<8;w++){ /* check which pixels are affected */
+ if(y+w >= y1 && y+w <= y2){
+ set_bg_pixel(&and_mask,&or_mask,w);
+ set_fg_pixel(&and_mask_side,&or_mask_side,w);
+ }
+
+ if(y+w == y1 || y+w == y2){ /* top and bottom line */
+ set_fg_pixel(&and_mask,&or_mask,w);
+ }
+ }
+
+ p = fb_bw8->mem + (y/8)*framebuffer->width + x1;
+ for(w=x1;w<=x2;w++){
+ if(w == x1 || w == x2)
+ *p = (*p & and_mask_side)|or_mask_side;
+ else
+ *p = (*p & and_mask)|or_mask;
+ p++;
+ }
+ }
+}
+
+/* draw box from cursor to (x,y) */
+void
+fb_bw8_boxto(uint16_t x,uint16_t y){
+ fb_bw8_box(framebuffer->cursor_x,framebuffer->cursor_y,x,y);
+ framebuffer->cursor_x = x;
+ framebuffer->cursor_y = y;
+}
+
+/* this is the most ridiculous function ever, because it has to
+ fiddle with two braindead bitmaps at once, both being
+ organized differently */
+
+/* draw text at current position, with current font and colours up
+ to a width of maxwidth pixels, return pixelwidth consumed */
+
+int
+fb_bw8_putstr(char *str,int maxwidth){
+ const struct fb_font *font = fb_fonts[framebuffer->font];
+ const struct fb_char *fchr;
+
+ int x1,y1,x2,y2; // will become bounding box
+ int w; // 0..7 while building bits per byte
+ int y; // coordinates in display
+ int char_x,char_y; // coordinates in font character
+ int bitmap_x,bitmap_y; // coordinates in character's bitmap
+ int byte_per_line; // depending on character width in font
+ int bitmap_offs,bitmap_bit; // offset inside bitmap, bit number of pixel
+ int fb8_offs; // offset to current pixel in framebuffer
+ uint8_t and_mask,or_mask; // to draw on framebuffer
+ uint8_t *p; // pointer into framebuffer memorya
+ int total_w; // total width
+
+ /* center, if maxwidth < 0 */
+ if (maxwidth < 0) {
+ total_w = 0;
+ /* count width of string */
+ for(p=(uint8_t *)str;*p;p++){
+ fchr = fb_font_get_char(font,*p);
+ if(!fchr) /* FIXME: Does '?' exist in every font? */
+ fchr = fb_font_get_char(font,'?');
+ total_w += fchr->width;
+
+ } // str
+ if (total_w <= framebuffer->width)
+ framebuffer->cursor_x =
+ (framebuffer->width - total_w) >> 1;
+ maxwidth = framebuffer->width;
+ }
+
+ x1 = framebuffer->cursor_x; // first col (incl!)
+ x2 = x1 + maxwidth - 1; // last col (incl!)
+ if(x2 >= framebuffer->width)
+ x2 = framebuffer->width - 1;
+
+ y1 = framebuffer->cursor_y - font->ascent + 1; // first row
+ y2 = y1 + font->height - 1; // last row
+
+#if 0
+ printf("%s: %d %d %d %d\n",__FUNCTION__,x1,y1,x2,y2);
+#endif
+
+ if(y1 < 0) // sanitize in case of overflow
+ y1 = 0;
+ if(y2 >= framebuffer->height)
+ y2 = framebuffer->height - 1;
+
+ fb8_offs = x1 + (y1 & 0xfff8)/8;
+
+ /* iterate over all characters */
+ for(;*str && framebuffer->cursor_x <= x2;str++){
+ fchr = fb_font_get_char(font,*str);
+ if(!fchr) /* FIXME: Does '?' exist in every font? */
+ fchr = fb_font_get_char(font,'?');
+
+ byte_per_line = (fchr->bbox_w+7)/8;;
+
+ /* character pixels, left to right */
+ for(char_x=0;
+ char_x<fchr->width && char_x + framebuffer->cursor_x <= x2;
+ char_x++
+ ){
+ /* character pixels, top to bottom, in stripes
+ of 8 to match LCD RAM organisation */
+ for(y=y1&0xfff8;y<=y2;y+=8){ // display lines
+ /* bitmap coordinates, X= left to right */
+ bitmap_x = char_x - fchr->bbox_x;
+ /* character coords. Y increases from
+ cursor upwards */
+ char_y = framebuffer->cursor_y-y;
+ /* bitmap index = height-(bitmap coords)-1 */
+ bitmap_y = fchr->bbox_h -
+ (char_y - fchr->bbox_y) - 1;
+
+ fb8_offs = framebuffer->cursor_x +
+ char_x + (y/8)*framebuffer->width;
+
+ and_mask = 0xff;
+ or_mask = 0x00;
+
+ /* top to bottom inside of a 8bit column */
+ for(w=0;w<8;w++,bitmap_y++){
+ /* inside drawing area? */
+ if(y+w < y1 || y+w > y2)
+ continue;
+
+ /* outside pixel data of this
+ character? */
+ if(bitmap_x < 0 ||
+ bitmap_x >= fchr->bbox_w ||
+ bitmap_y < 0 ||
+ bitmap_y >= fchr->bbox_h
+ )
+ goto outside_char_bitmap;
+
+ /* check bit in pixel data for
+ this character */
+ bitmap_offs = bitmap_x/8+
+ bitmap_y*byte_per_line;
+ bitmap_bit = 7-(bitmap_x%8);
+
+ /* bit is set */
+ if(fchr->data[bitmap_offs] &
+ (1<<bitmap_bit)){
+ set_fg_pixel(&and_mask,
+ &or_mask,w);
+ } else { // unset, or outside bitmap
+outside_char_bitmap:
+ set_bg_pixel(&and_mask,
+ &or_mask,w);
+ }
+ } // for(w...)
+ /* adjust byte in framebuffer */
+ p = fb_bw8->mem + fb8_offs;
+ *p = ( *p & and_mask ) | or_mask;
+ } // for(y...)
+ } // for(char_x...)
+ framebuffer->cursor_x += char_x;
+ } // str
+
+ x2 = framebuffer->cursor_x;
+ fb_bw8_update_damage(x1,y1,x2,y2);
+ return x2-x1;
+}
+
+int
+fb_bw8_putchar(char c,int maxwidth){
+ char tmp[2];
+ tmp[0]=c;
+ tmp[1]=c;
+ return fb_bw8_putstr(tmp,maxwidth);
+}
diff --git a/src/target/firmware/fb/fb_dummy.c b/src/target/firmware/fb/fb_dummy.c
new file mode 100644
index 00000000..cb053de4
--- /dev/null
+++ b/src/target/firmware/fb/fb_dummy.c
@@ -0,0 +1,70 @@
+/*
+ "hardware" driver for a dummy framebuffer. Used when no
+ display hardware is supported
+ */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <defines.h>
+
+static void
+fb_dummy_init(){
+}
+
+static void
+fb_dummy_clear(){
+}
+
+static void
+fb_dummy_boxto(uint16_t x,uint16_t y){
+ framebuffer->cursor_x = x;
+ framebuffer->cursor_y = y;
+}
+
+static void
+fb_dummy_lineto(uint16_t x,uint16_t y){
+ framebuffer->cursor_x = x;
+ framebuffer->cursor_y = y;
+}
+
+static int
+fb_dummy_putstr(__unused char *c, __unused int maxwidth){
+ return 0;
+}
+
+static void
+fb_dummy_flush(){
+}
+
+struct framebuffer fb_dummy_framebuffer = {
+ .name = "dummyfb",
+ .init = fb_dummy_init,
+ .clear = fb_dummy_clear,
+ .boxto = fb_dummy_boxto,
+ .lineto = fb_dummy_lineto,
+ .putstr = fb_dummy_putstr,
+ .flush = fb_dummy_flush,
+ .width = 128,
+ .height = 64
+};
+
+struct framebuffer *framebuffer = & fb_dummy_framebuffer;
diff --git a/src/target/firmware/fb/fb_rgb332.c b/src/target/firmware/fb/fb_rgb332.c
new file mode 100644
index 00000000..08d64e13
--- /dev/null
+++ b/src/target/firmware/fb/fb_rgb332.c
@@ -0,0 +1,305 @@
+/* utility functions for a color framebuffer organized
+ as one pixel per byte, with bits mapped as RRRGGGBB.
+ This matches the SSD1783 LC Display Controller used
+ on the Motorola C155 */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <fb/fb_rgb332.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+fb_rgb332_clear(){
+ int i,n;
+
+ /* bytes to clear */
+ n = framebuffer->height * framebuffer->width;
+ for(i=0;i<n;i++)
+ fb_rgb332->mem[i]=0xff; /* white */
+
+ /* mark everything as dirty */
+ fb_rgb332->damage_x1 = 0;
+ fb_rgb332->damage_x2 = framebuffer->width;
+ fb_rgb332->damage_y1 = 0;
+ fb_rgb332->damage_y2 = framebuffer->height;
+}
+
+/* update damage rectangle to include the area
+ x1,y1 (upper left) to x2,y2 (lower right)
+ Note that all pixels *including* x1y2 and x2y2 are
+ marked as dirty */
+static void
+fb_rgb332_update_damage(
+ uint16_t x1,uint16_t y1, /* left upper corner (inclusive) */
+ uint16_t x2,uint16_t y2 /* right lower corner (inclusive) */
+){
+ fb_sanitize_box(&x1,&y1,&x2,&y2);
+
+ x2++; /* see definition of fb_rgb332->damage_x2/y2 */
+ y2++;
+
+ /* maybe currently everything is clean? */
+ if(fb_rgb332->damage_x1 == fb_rgb332->damage_x2 ||
+ fb_rgb332->damage_y1 == fb_rgb332->damage_y2
+ ){
+ fb_rgb332->damage_x1 = x1;
+ fb_rgb332->damage_y1 = y1;
+ fb_rgb332->damage_x2 = x2;
+ fb_rgb332->damage_y2 = y2;
+ return;
+ }
+
+ /* grow damage box */
+ if(x1 < fb_rgb332->damage_x1)
+ fb_rgb332->damage_x1 = x1;
+ if(y1 < fb_rgb332->damage_y1)
+ fb_rgb332->damage_y1 = y1;
+ if(x2 > fb_rgb332->damage_x2)
+ fb_rgb332->damage_x2 = x2;
+ if(y2 > fb_rgb332->damage_y2)
+ fb_rgb332->damage_y2 = y2;
+#if 0
+ printf("%s: damage now %d %d %d %d\n",
+ __FUNCTION__,fb_rgb332->damage_x1,fb_rgb332->damage_y1,
+ fb_rgb332->damage_x2,fb_rgb332->damage_y2);
+#endif
+}
+
+/* we trust gcc to move this expensive bitshifting out of
+ the loops in the drawing funtcions */
+static uint8_t rgb_to_pixel(uint32_t color){
+ uint8_t ret;
+ ret = (FB_COLOR_TO_R(color) & 0xe0); /* 765 = RRR */
+ ret |= (FB_COLOR_TO_G(color) & 0xe0) >> 3; /* 432 = GGG */
+ ret |= (FB_COLOR_TO_B(color) & 0xc0) >> 6; /* 10 = BB */
+ return ret;
+}
+
+static void set_pix(uint8_t *pixel,uint32_t color){
+ if(color == FB_COLOR_TRANSP)
+ return;
+ *pixel = rgb_to_pixel(color);
+}
+
+static void set_fg(uint8_t *pixel){
+ set_pix(pixel,framebuffer->fg_color);
+}
+
+static void set_bg(uint8_t *pixel){
+ set_pix(pixel,framebuffer->bg_color);
+}
+
+void fb_rgb332_boxto(uint16_t x2,uint16_t y2)
+{
+ uint16_t x1 = framebuffer->cursor_x;
+ uint16_t y1 = framebuffer->cursor_y;
+ int x,y;
+ uint8_t *p;
+
+ framebuffer->cursor_x = x2;
+ framebuffer->cursor_y = y2;
+
+ fb_sanitize_box(&x1,&y1,&x2,&y2);
+ fb_rgb332_update_damage(x1,y1,x2,y2);
+
+ for(y=y1; y<=y2; y++){
+ p = & fb_rgb332->mem[x1 + framebuffer->width * y];
+ for(x=x1;x<=x2;x++){
+ set_bg(p);
+ if(y==y1 || y==y2 || x==x1 || x==x2) /* border */
+ set_fg(p);
+ p++;
+ }
+ }
+}
+
+/* draw a line like Brensenham did... (roughly) */
+void fb_rgb332_lineto(uint16_t x2,uint16_t y2){
+ uint8_t *p,pixel; /* framebuffer pointer */
+ int delta_regular; /* framebuffer offset per step */
+ int delta_step; /* " */
+
+ uint16_t x1 = framebuffer->cursor_x; /* start */
+ uint16_t y1 = framebuffer->cursor_y;
+
+ int t,tmax; /* counter for steps */
+ int err_inc,err_accu=0; /* error delta and accumulator for */
+ /* Brensenham's algorhithm */
+
+ fb_limit_fb_range(&x1,&y1);
+ fb_limit_fb_range(&x2,&y2);
+ fb_rgb332_update_damage(x1,y1,x2,y2);
+
+ framebuffer->cursor_x = x2; /* end pixel */
+ framebuffer->cursor_y = y2;
+
+ /* pointer to first pixel, pixel value in FB memory */
+ p = fb_rgb332->mem + framebuffer->width * y1 + x1;
+ pixel = rgb_to_pixel(framebuffer->fg_color);
+
+ if(abs(x2-x1) >= abs(y2-y1)){ /* shallow line */
+ /* set pointer deltas for directions */
+ delta_regular = 1; /* X */
+ if(x2 < x1)
+ delta_regular = -delta_regular;
+ delta_step = framebuffer->width; /* Y */
+ if(y2 < y1)
+ delta_step = -delta_step;
+ tmax = abs(x2-x1);
+ err_inc = abs(y2-y1);
+ } else { /* steep line */
+ delta_regular = framebuffer->width; /* Y */
+ if(y2 < y1)
+ delta_regular = -delta_regular;
+ delta_step = 1; /* X */
+ if(x2 < x1)
+ delta_step = -1;
+ tmax = abs(y2-y1);
+ err_inc = abs(x2-y1);
+ }
+
+#if 0
+ printf("%s: (%d,%d) -> (%d,%d) step=%d regular=%d err_inc=%d tmax=%d\n",
+ __FUNCTION__,x1,y1,x2,y2,delta_step,delta_regular,err_inc,tmax);
+#endif
+
+ for(t=0;t<=tmax;t++){
+ *p = pixel;
+ err_accu += err_inc;
+ if(err_accu >= tmax){
+ p += delta_step;
+ err_accu -= tmax;
+ }
+ p += delta_regular;
+ }
+}
+
+int fb_rgb332_putstr(char *str,int maxwidth){
+ const struct fb_font *font = fb_fonts[framebuffer->font];
+ const struct fb_char *fchr;
+
+ int x1,y1,x2,y2; // will become bounding box
+ int y; // coordinates in display
+ int char_x=0,char_y; // coordinates in font character
+ int bitmap_x,bitmap_y; // coordinates in character's bitmap
+ int byte_per_line; // depending on character width in font
+ int bitmap_offs,bitmap_bit; // offset inside bitmap, bit number of pixel
+ uint8_t *p,fgpixel,bgpixel,trans; // pointer into framebuffer memory
+ int total_w; // total width
+
+ /* center, if maxwidth < 0 */
+ if (maxwidth < 0) {
+ total_w = 0;
+ /* count width of string */
+ for(p=(uint8_t *)str;*p;p++){
+ fchr = fb_font_get_char(font,*p);
+ if(!fchr) /* FIXME: Does '?' exist in every font? */
+ fchr = fb_font_get_char(font,'?');
+ total_w += fchr->width;
+
+ } // str
+ if (total_w <= framebuffer->width)
+ framebuffer->cursor_x =
+ (framebuffer->width - total_w) >> 1;
+ else
+ framebuffer->cursor_x = 1;
+ maxwidth = framebuffer->width;
+ }
+
+ x1 = framebuffer->cursor_x; // first col (incl!)
+ x2 = x1 + maxwidth - 1; // last col (incl!)
+ if(x2 >= framebuffer->width)
+ x2 = framebuffer->width - 1;
+
+ y1 = framebuffer->cursor_y - font->ascent + 1; // first row
+ y2 = y1 + font->height - 1; // last row
+
+ fgpixel = rgb_to_pixel(framebuffer->fg_color);
+ bgpixel = rgb_to_pixel(framebuffer->bg_color);
+ trans = (framebuffer->bg_color == FB_COLOR_TRANSP);
+
+ if(y1 < 0) // sanitize in case of overflow
+ y1 = 0;
+ if(y2 >= framebuffer->height)
+ y2 = framebuffer->height - 1;
+
+ /* iterate over all characters */
+ for(;*str && framebuffer->cursor_x <= x2;str++){
+ fchr = fb_font_get_char(font,*str);
+ if(!fchr) /* FIXME: Does '?' exist in every font? */
+ fchr = fb_font_get_char(font,'?');
+ if(!fchr)
+ return 0;
+ byte_per_line = (fchr->bbox_w+7)/8;
+
+ for(y=y1;y<=y2;y++){
+ p=fb_rgb332->mem+y*framebuffer->width;
+ p+=framebuffer->cursor_x;
+
+ for(char_x=0;
+ char_x<fchr->width &&
+ char_x+framebuffer->cursor_x <= x2;
+ char_x++
+ ){
+ /* bitmap coordinates, X= left to right */
+ bitmap_x = char_x - fchr->bbox_x;
+ /* character coords. Y increases from
+ cursor upwards */
+ char_y = framebuffer->cursor_y-y;
+ /* bitmap index = height-(bitmap coords)-1 */
+ bitmap_y = fchr->bbox_h -
+ (char_y - fchr->bbox_y) - 1;
+
+ /* outside pixel data of this
+ character? */
+ if(bitmap_x < 0 ||
+ bitmap_x >= fchr->bbox_w ||
+ bitmap_y < 0 ||
+ bitmap_y >= fchr->bbox_h
+ )
+ goto outside_char_bitmap;
+
+ /* check bit in pixel data for
+ this character */
+ bitmap_offs=bitmap_x/8+bitmap_y*byte_per_line;
+ bitmap_bit=7-(bitmap_x%8);
+
+ /* bit is set */
+ if(fchr->data[bitmap_offs]&(1<<bitmap_bit)){
+ *p = fgpixel;
+ } else { // unset, or outside bitmap
+outside_char_bitmap:
+ if (!trans)
+ *p = bgpixel;
+ }
+ p++;
+ } // for(x...)
+ } // for(char_x...)
+ framebuffer->cursor_x += char_x;
+ } // str
+
+ x2 = framebuffer->cursor_x;
+ fb_rgb332_update_damage(x1,y1,x2,y2);
+ return x2-x1;
+}
+
diff --git a/src/target/firmware/fb/fb_s6b33b1x.c b/src/target/firmware/fb/fb_s6b33b1x.c
new file mode 100644
index 00000000..3629a101
--- /dev/null
+++ b/src/target/firmware/fb/fb_s6b33b1x.c
@@ -0,0 +1,193 @@
+/* Framebuffer implementation - combined Sunplus SPCA552E and
+ * Samsung S6B33B1X LCD driver - as used in the Pirelli DP-L10 */
+
+/* (C) 2012 by Steve Markgraf <steve@steve-m.de>
+ *
+ * based on fb_ssd1783.c:
+ * (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <fb/fb_rgb332.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <delay.h>
+#include <memory.h>
+
+#define S6B33B1X_WIDTH 128
+#define S6B33B1X_HEIGHT 128
+#define LCD_INVIS_X_PIXELS 4
+
+#define ARMIO_LATCH_OUT 0xfffe4802
+#define nCS4_ADDR 0x02800000
+
+static uint8_t fb_s6b33b1x_mem[S6B33B1X_WIDTH * S6B33B1X_HEIGHT];
+
+enum s6b33b1x_cmdflag { CMD, DATA, END };
+
+struct s6b33b1x_cmdlist {
+ enum s6b33b1x_cmdflag is_cmd:8; /* 1: is a command, 0: is data, 2: end marker! */
+ uint8_t data; /* 8 bit to send to LC display */
+} __attribute__((packed));
+
+static const struct s6b33b1x_cmdlist
+s6b33b1x_initdata[] = {
+ { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */
+ { DATA, 0x00 }, /* DATA: everything off */
+ { CMD, 0x02 }, /* CMD Oscillation Mode Set */
+ { DATA, 0x00 }, /* DATA: oscillator off */
+ { CMD, 0x2c }, /* CMD Standby Mode off */
+ { CMD, 0x50 }, /* CMD Display off */
+ { CMD, 0x02 }, /* CMD Oscillation Mode Set */
+ { DATA, 0x01 }, /* DATA: oscillator on */
+ { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */
+ { DATA, 0x01 }, /* DATA: Booster 1 on */
+ { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */
+ { DATA, 0x09 }, /* DATA: Booster 1 on, OP-AMP on */
+ { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */
+ { DATA, 0x0b }, /* DATA: Booster 1 + 2 on, OP-AMP on */
+ { CMD, 0x26 }, /* CMD DCDC and AMP ON/OFF set */
+ { DATA, 0x0f }, /* DATA: Booster 1 + 2 + 3 on, OP-AMP on */
+ { CMD, 0x20 }, /* CMD DC-DC Select */
+ { DATA, 0x01 }, /* DATA: step up x1.5 */
+ { CMD, 0x24 }, /* CMD DCDC Clock Division Set */
+ { DATA, 0x0a }, /* DATA: fPCK = fOSC/6 */
+ { CMD, 0x2a }, /* CMD Contrast Control */
+ { DATA, 0x2d }, /* DATA: default contrast */
+ { CMD, 0x30 }, /* CMD Adressing mode set */
+ { DATA, 0x0b }, /* DATA: 65536 color mode */
+ { CMD, 0x10 }, /* CMD Driver output mode set */
+ { DATA, 0x03 }, /* DATA: Display duty: 1/132 */
+ { CMD, 0x34 }, /* CMD N-line inversion set */
+ { DATA, 0x88 }, /* DATA: inversion on, one frame, every 8 blocks */
+ { CMD, 0x40 }, /* CMD Entry mode set */
+ { DATA, 0x00 }, /* DATA: Y address counter mode */
+ { CMD, 0x28 }, /* CMD Temperature Compensation set */
+ { DATA, 0x01 }, /* DATA: slope -0.05%/degC */
+ { CMD, 0x32 }, /* CMD ROW vector mode set */
+ { DATA, 0x01 }, /* DATA: every 2 subgroup */
+ { CMD, 0x51 }, /* CMD Display on */
+ { END, 0x00 }, /* MARKER: end of list */
+};
+
+static void fb_s6b33b1x_send_cmdlist(const struct s6b33b1x_cmdlist *p)
+{
+ while(p->is_cmd != END){
+ writew(p->data, nCS4_ADDR);
+ p++;
+ }
+}
+
+static void fb_spca_write(uint16_t addr, uint16_t val)
+{
+ writew(addr, nCS4_ADDR);
+ writew(val , nCS4_ADDR | 2);
+}
+
+static void fb_spca_init(void)
+{
+ uint16_t reg;
+
+ /* Initialize Sunplus SPCA552E Media Controller for bypass mode */
+ fb_spca_write(0x7e, 0x00); /* internal register access */
+ delay_ms(10);
+ fb_spca_write(0x7a, 0x00); /* keep CPU in reset state */
+ delay_ms(10);
+ fb_spca_write(0x7f, 0x00); /* select main page */
+ delay_ms(5);
+ fb_spca_write(0x72, 0x07); /* don't reshape timing, 16 bit mode */
+ fb_spca_write(0x14, 0x03);
+ fb_spca_write(0x7f, 0x00); /* select main page */
+ delay_ms(5);
+ fb_spca_write(0x06, 0xff);
+ fb_spca_write(0x7f, 0x09);
+ fb_spca_write(0x19, 0x08); /* backlight: 0x08 is on, 0x0c is off */
+ fb_spca_write(0x23, 0x18);
+
+ /* enable bypass mode */
+ reg = readw(ARMIO_LATCH_OUT);
+ reg |= (1 << 7);
+ writew(reg, ARMIO_LATCH_OUT);
+}
+
+static void fb_s6b33b1x_init(void)
+{
+ printf("%s: initializing LCD.\n",__FUNCTION__);
+
+ fb_spca_init();
+ fb_s6b33b1x_send_cmdlist(s6b33b1x_initdata);
+}
+
+static void fb_s6b33b1x_flush(void)
+{
+ int x,y;
+ uint8_t *p;
+ struct s6b33b1x_cmdlist prepare_disp_write_cmds[] = {
+ { CMD, 0x42 }, /* set column address */
+ { DATA, fb_rgb332->damage_x1 + LCD_INVIS_X_PIXELS },
+ { DATA, fb_rgb332->damage_x2 + LCD_INVIS_X_PIXELS - 1 },
+ { CMD, 0x43 }, /* set page address (Y) */
+ { DATA, fb_rgb332->damage_y1 },
+ { DATA, fb_rgb332->damage_y2 - 1 },
+ { END, 0x00 }
+ };
+
+ /* If everything's clean, just return */
+ if(fb_rgb332->damage_x1 == fb_rgb332->damage_x2 ||
+ fb_rgb332->damage_y1 == fb_rgb332->damage_y2) {
+ printf("%s: no damage\n",__FUNCTION__);
+ return;
+ }
+
+ fb_s6b33b1x_send_cmdlist(prepare_disp_write_cmds);
+
+ for(y=fb_rgb332->damage_y1;y<fb_rgb332->damage_y2;y++) {
+ p = & fb_rgb332->mem[y * framebuffer->width]; // start of line
+ p += fb_rgb332->damage_x1; // start of damage area
+
+ for(x=fb_rgb332->damage_x1; x<fb_rgb332->damage_x2; x++) {
+ uint16_t data = rgb332_to_565(*p++);
+ writew(data , nCS4_ADDR | 2);
+ }
+ }
+
+ fb_rgb332->damage_x1 = fb_rgb332->damage_x2 = 0;
+ fb_rgb332->damage_y1 = fb_rgb332->damage_y2 = 0;
+}
+
+static struct framebuffer fb_s6b33b1x_framebuffer = {
+ .name = "s6b33b1x",
+ .init = fb_s6b33b1x_init,
+ .clear = fb_rgb332_clear,
+ .boxto = fb_rgb332_boxto,
+ .lineto = fb_rgb332_lineto,
+ .putstr = fb_rgb332_putstr,
+ .flush = fb_s6b33b1x_flush,
+ .width = S6B33B1X_WIDTH,
+ .height = S6B33B1X_HEIGHT
+};
+
+static struct fb_rgb332 fb_s6b33b1x_rgb332 = {
+ .mem = fb_s6b33b1x_mem
+};
+
+struct framebuffer *framebuffer = &fb_s6b33b1x_framebuffer;
+struct fb_rgb332 *fb_rgb332 = &fb_s6b33b1x_rgb332;
diff --git a/src/target/firmware/fb/fb_ssd1783.c b/src/target/firmware/fb/fb_ssd1783.c
new file mode 100644
index 00000000..cacdce03
--- /dev/null
+++ b/src/target/firmware/fb/fb_ssd1783.c
@@ -0,0 +1,204 @@
+/* Framebuffer implementation - SSD1783 LCD driver for C155 */
+/* Based on ssd1783.c by Steve Markgraf and Harald Welte */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <fb/fb_rgb332.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <delay.h>
+#include <uwire.h>
+#include <calypso/clock.h>
+
+#define SSD1783_WIDTH 98
+#define SSD1783_HEIGHT 67
+#define SSD1783_UWIRE_BITLEN 9
+#define SSD1783_DEV_ID 0
+
+#define LCD_TOP_FREE_ROWS 3
+#define LCD_LEFT_FREE_COLS 0
+#define PIXEL_BYTES 3
+#define FONT_HEIGHT 8
+#define FONT_WIDTH 8
+
+static uint8_t fb_ssd1783_mem[SSD1783_WIDTH * SSD1783_HEIGHT];
+
+enum ssd1783_cmdflag { CMD, DATA, END };
+
+struct ssd1783_cmdlist {
+ enum ssd1783_cmdflag is_cmd:8; /* 1: is a command, 0: is data, 2: end marker! */
+ uint8_t data; /* 8 bit to send to LC display */
+} __attribute__((packed));
+
+static const struct ssd1783_cmdlist
+ssd1783_initdata[] = {
+ { CMD, 0xD1 }, /* CMD set internal oscillator on */
+ { CMD, 0x94 }, /* CMD leave sleep mode */
+ { CMD, 0xbb }, /* CMD Set COM Output Scan Direction: */
+ { DATA, 0x01 }, /* DATA: 01: COM0-79, then COM159-80 */
+/* -------- DIFFERENT FROM ORIGINAL CODE: -------------- */
+/* we use 8bit per pixel packed RGB 332 */
+ { CMD, 0xbc }, /* CMD Set Data Output Scan Direction */
+ { DATA, 0x00 }, /* DATA: column scan, normal rotation, normal display */
+ { DATA, 0x00 }, /* DATA: RGB color arrangement R G B R G B ... */
+/*-->*/ { DATA, 0x01 }, /* DATA: 8 bit per pixel mode MSB <RRRGGGBB> LSB */
+/* --------- /DIFFERENT ---------- */
+ { CMD, 0xce }, /* CMD Set 256 Color Look Up Table LUT */
+ { DATA, 0x00 }, /* DATA red 000 */
+ { DATA, 0x03 }, /* DATA red 001 */
+ { DATA, 0x05 }, /* DATA red 010 */
+ { DATA, 0x07 }, /* DATA red 011 */
+ { DATA, 0x09 }, /* DATA red 100 */
+ { DATA, 0x0b }, /* DATA red 101 */
+ { DATA, 0x0d }, /* DATA red 110 */
+ { DATA, 0x0f }, /* DATA red 111 */
+ { DATA, 0x00 }, /* DATA green 000 */
+ { DATA, 0x03 }, /* DATA green 001 */
+ { DATA, 0x05 }, /* DATA green 010 */
+ { DATA, 0x07 }, /* DATA green 011 */
+ { DATA, 0x09 }, /* DATA green 100 */
+ { DATA, 0x0b }, /* DATA green 101 */
+ { DATA, 0x0d }, /* DATA green 110 */
+ { DATA, 0x0f }, /* DATA green 111 */
+ { DATA, 0x00 }, /* DATA blue 00 */
+ { DATA, 0x05 }, /* DATA blue 01 */
+ { DATA, 0x0a }, /* DATA blue 10 */
+ { DATA, 0x0f }, /* DATA blue 11 */
+ { CMD, 0xca }, /* CMD Set Display Control - Driver Duty Selection */
+ { DATA, 0xff }, // can't find description of the values in the original
+ { DATA, 0x10 }, // display/ssd1783.c in my datasheet :-(
+ { DATA, 0x01 }, //
+ { CMD, 0xab }, /* CMD Set Scroll Start */
+ { DATA, 0x00 }, /* DATA: Starting address at block 0 */
+ { CMD, 0x20 }, /* CMD Set power control register */
+ { DATA, 0x0b }, /* DATA: booster 6x, reference gen. & int regulator */
+ { CMD, 0x81 }, /* CMD Contrast Lvl & Int. Regul. Resistor Ratio */
+ { DATA, 0x29 }, /* DATA: contrast = 0x29 */
+ { DATA, 0x05 }, /* DATA: 0x05 = 0b101 -> 1+R2/R1 = 11.37 */
+ { CMD, 0xa7 }, /* CMD Invert Display */
+ { CMD, 0x82 }, /* CMD Set Temperature Compensation Coefficient */
+ { DATA, 0x00 }, /* DATA: Gradient is -0.10 % / degC */
+ { CMD, 0xfb }, /* CMD Set Biasing Ratio */
+ { DATA, 0x03 }, /* DATA: 1/10 bias */
+ { CMD, 0xf2 }, /* CMD Set Frame Frequency and N-line inversion */
+ { DATA, 0x08 }, /* DATA: 75 Hz (POR) */
+ { DATA, 0x06 }, /* DATA: n-line inversion: 6 lines */
+ { CMD, 0xf7 }, /* CMD Select PWM/FRC Select Full Col./8col mode */
+ { DATA, 0x28 }, /* DATA: always 0x28 */
+ { DATA, 0x8c }, /* DATA: 4bit PWM + 2 bit FRC */
+ { DATA, 0x05 }, /* DATA: full color mode */
+ { CMD, 0xaf }, /* CMD Display On */
+ { END, 0x00 }, /* MARKER: end of list */
+};
+
+static void
+fb_ssd1783_send_cmdlist(const struct ssd1783_cmdlist *p){
+ int i=0;
+ while(p->is_cmd != END){
+ uint16_t sendcmd = p->data;
+ if(p->is_cmd == DATA)
+ sendcmd |= 0x0100; /* 9th bit is cmd/data flag */
+ uwire_xfer(SSD1783_DEV_ID, SSD1783_UWIRE_BITLEN, &sendcmd, NULL);
+ p++;
+ i++;
+ }
+}
+
+static void
+fb_ssd1783_init(void){
+ printf("%s: initializing LCD.\n",__FUNCTION__);
+ calypso_reset_set(RESET_EXT, 0);
+ delay_ms(5);
+ uwire_init();
+ delay_ms(5);
+ fb_ssd1783_send_cmdlist(ssd1783_initdata);
+}
+
+/* somehow the palette is messed up, RRR seems to have the
+ bits reversed! R0 R1 R2 G G G B B ---> R2 R1 R0 G G G B B */
+static uint8_t fix_rrr(uint8_t v){
+ return (v & 0x5f) | (v & 0x80) >> 2 | (v & 0x20) << 2;
+}
+
+static void
+fb_ssd1783_flush(void){
+ int x,y;
+ uint8_t *p;
+ struct ssd1783_cmdlist prepare_disp_write_cmds[] = {
+ { CMD, 0x15 }, /* set column address */
+ { DATA, fb_rgb332->damage_x1 },
+ { DATA, fb_rgb332->damage_x2-1 },
+ { CMD, 0x75 }, /* set page address (Y) */
+ { DATA, fb_rgb332->damage_y1 },
+ { DATA, fb_rgb332->damage_y2-1 },
+ { CMD, 0x5c }, /* enter write display ram mode */
+ { END, 0x00 }
+ };
+ struct ssd1783_cmdlist nop[] = {
+ { CMD, 0x25 }, // NOP command
+ { END, 0x00 }
+ };
+
+ /* If everything's clean, just return */
+ if(fb_rgb332->damage_x1 == fb_rgb332->damage_x2 ||
+ fb_rgb332->damage_y1 == fb_rgb332->damage_y2){
+ printf("%s: no damage\n",__FUNCTION__);
+ return;
+ }
+
+ fb_ssd1783_send_cmdlist(prepare_disp_write_cmds);
+
+ for(y=fb_rgb332->damage_y1;y<fb_rgb332->damage_y2;y++){
+ p = & fb_rgb332->mem[y * framebuffer->width]; // start of line
+ p += fb_rgb332->damage_x1; // start of damage area
+
+ for(x=fb_rgb332->damage_x1;x<fb_rgb332->damage_x2;x++){
+ uint16_t data = 0x0100 | fix_rrr(*p++); // dummy data
+ uwire_xfer(SSD1783_DEV_ID, SSD1783_UWIRE_BITLEN,
+ &data, NULL);
+ }
+ }
+ fb_ssd1783_send_cmdlist(nop);
+
+ fb_rgb332->damage_x1 = fb_rgb332->damage_x2 = 0;
+ fb_rgb332->damage_y1 = fb_rgb332->damage_y2 = 0;
+}
+
+static struct framebuffer fb_ssd1783_framebuffer = {
+ .name = "ssd1783",
+ .init = fb_ssd1783_init,
+ .clear = fb_rgb332_clear,
+ .boxto = fb_rgb332_boxto,
+ .lineto = fb_rgb332_lineto,
+ .putstr = fb_rgb332_putstr,
+ .flush = fb_ssd1783_flush,
+ .width = SSD1783_WIDTH,
+ .height = SSD1783_HEIGHT
+};
+
+static struct fb_rgb332 fb_ssd1783_rgb332 = {
+ .mem = fb_ssd1783_mem
+};
+
+struct framebuffer *framebuffer = &fb_ssd1783_framebuffer;
+struct fb_rgb332 *fb_rgb332 = &fb_ssd1783_rgb332;
diff --git a/src/target/firmware/fb/fb_ssd1963.c b/src/target/firmware/fb/fb_ssd1963.c
new file mode 100644
index 00000000..361434e4
--- /dev/null
+++ b/src/target/firmware/fb/fb_ssd1963.c
@@ -0,0 +1,196 @@
+/* Framebuffer implementation - SSD1963 (S1D15G14 clone) LCD driver for J100i */
+/* Based on ssd1963.c by Steve Markgraf and Harald Welte */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ * (C) 2012 by Steve Markgraf <steve@steve-m.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <fb/fb_rgb332.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <delay.h>
+#include <uwire.h>
+#include <calypso/clock.h>
+
+#define SSD1963_WIDTH 96
+#define SSD1963_HEIGHT 64
+#define SSD1963_UWIRE_BITLEN 9
+#define SSD1963_DEV_ID 0
+
+static uint8_t fb_ssd1963_mem[SSD1963_WIDTH * SSD1963_HEIGHT];
+
+enum ssd1963_cmdflag { CMD, DATA, END };
+
+struct ssd1963_cmdlist {
+ enum ssd1963_cmdflag is_cmd:8; /* 1: is a command, 0: is data, 2: end marker! */
+ uint8_t data; /* 8 bit to send to LC display */
+} __attribute__((packed));
+
+static const struct ssd1963_cmdlist
+ssd1963_initdata[] = {
+ { CMD, 0xb6 }, /* CMD Display Control, set panel parameters */
+ { DATA, 0x4b },
+ { DATA, 0xf1 },
+ { DATA, 0x40 },
+ { DATA, 0x40 },
+ { DATA, 0x00 },
+ { DATA, 0x8c },
+ { DATA, 0x00 },
+ { CMD, 0x3a }, /* CMD Set pixel format */
+ { DATA, 0x02 }, /* DATA: 8 bit per pixel */
+ { CMD, 0x2d }, /* Colour set, RGB332 -> RGB 565 mapping */
+ { DATA, 0x00 }, /* DATA red 000 */
+ { DATA, 0x04 }, /* DATA red 001 */
+ { DATA, 0x09 }, /* DATA red 010 */
+ { DATA, 0x0d }, /* DATA red 011 */
+ { DATA, 0x12 }, /* DATA red 100 */
+ { DATA, 0x16 }, /* DATA red 101 */
+ { DATA, 0x1b }, /* DATA red 110 */
+ { DATA, 0x1f }, /* DATA red 111 */
+ { DATA, 0x00 }, /* Those bytes are probably a second palette */
+ { DATA, 0x00 }, /* for an unused powersaving mode with reduced colors */
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 }, /* DATA green 000 */
+ { DATA, 0x09 }, /* DATA green 001 */
+ { DATA, 0x12 }, /* DATA green 010 */
+ { DATA, 0x1b }, /* DATA green 011 */
+ { DATA, 0x24 }, /* DATA green 100 */
+ { DATA, 0x2d }, /* DATA green 101 */
+ { DATA, 0x36 }, /* DATA green 110 */
+ { DATA, 0x3f }, /* DATA green 111 */
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 }, /* DATA blue 00 */
+ { DATA, 0x0a }, /* DATA blue 01 */
+ { DATA, 0x15 }, /* DATA blue 10 */
+ { DATA, 0x1f }, /* DATA blue 11 */
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { DATA, 0x00 },
+ { CMD, 0x11 }, /* CMD Exit sleep mode*/
+ { CMD, 0xba }, /* CMD Set contrast/Electronic Volume Control */
+ { DATA, 0x5b }, /* DATA: */
+ { DATA, 0x84 }, /* DATA: */
+ { CMD, 0x36 }, /* CMD Memory access control */
+ { DATA, 0x00 }, /* DATA: */
+ { CMD, 0x13 }, /* CMD Enter normal mode */
+ { CMD, 0x29 }, /* CMD Set display on */
+ { END, 0x00 }, /* MARKER: end of list */
+};
+
+static void
+fb_ssd1963_send_cmdlist(const struct ssd1963_cmdlist *p) {
+ int i=0;
+ while(p->is_cmd != END){
+ uint16_t sendcmd = p->data;
+ if(p->is_cmd == DATA)
+ sendcmd |= 0x0100; /* 9th bit is cmd/data flag */
+ uwire_xfer(SSD1963_DEV_ID, SSD1963_UWIRE_BITLEN, &sendcmd, NULL);
+ p++;
+ i++;
+ }
+}
+
+static void
+fb_ssd1963_init(void){
+ printf("%s: initializing LCD.\n",__FUNCTION__);
+ calypso_reset_set(RESET_EXT, 0);
+ delay_ms(5);
+ uwire_init();
+ delay_ms(5);
+ fb_ssd1963_send_cmdlist(ssd1963_initdata);
+}
+
+static void
+fb_ssd1963_flush(void){
+ int x,y;
+ uint8_t *p;
+ struct ssd1963_cmdlist prepare_disp_write_cmds[] = {
+ { CMD, 0x2a }, /* set column address */
+ { DATA, fb_rgb332->damage_x1 },
+ { DATA, fb_rgb332->damage_x2-1 },
+ { CMD, 0x2b }, /* set page address (Y) */
+ { DATA, fb_rgb332->damage_y1 },
+ { DATA, fb_rgb332->damage_y2-1 },
+ { CMD, 0x2c }, /* enter write display ram mode */
+ { END, 0x00 }
+ };
+ struct ssd1963_cmdlist nop[] = {
+ { CMD, 0x00 }, // NOP command
+ { END, 0x00 }
+ };
+
+ /* If everything's clean, just return */
+ if(fb_rgb332->damage_x1 == fb_rgb332->damage_x2 ||
+ fb_rgb332->damage_y1 == fb_rgb332->damage_y2) {
+ printf("%s: no damage\n",__FUNCTION__);
+ return;
+ }
+
+ fb_ssd1963_send_cmdlist(prepare_disp_write_cmds);
+
+ for(y=fb_rgb332->damage_y1;y<fb_rgb332->damage_y2;y++) {
+ p = & fb_rgb332->mem[y * framebuffer->width]; // start of line
+ p += fb_rgb332->damage_x1; // start of damage area
+
+ for(x=fb_rgb332->damage_x1;x<fb_rgb332->damage_x2;x++) {
+ uint16_t data = 0x0100 | *p++;
+ uwire_xfer(SSD1963_DEV_ID, SSD1963_UWIRE_BITLEN,
+ &data, NULL);
+ }
+ }
+ fb_ssd1963_send_cmdlist(nop);
+
+ fb_rgb332->damage_x1 = fb_rgb332->damage_x2 = 0;
+ fb_rgb332->damage_y1 = fb_rgb332->damage_y2 = 0;
+}
+
+static struct framebuffer fb_ssd1963_framebuffer = {
+ .name = "ssd1963",
+ .init = fb_ssd1963_init,
+ .clear = fb_rgb332_clear,
+ .boxto = fb_rgb332_boxto,
+ .lineto = fb_rgb332_lineto,
+ .putstr = fb_rgb332_putstr,
+ .flush = fb_ssd1963_flush,
+ .width = SSD1963_WIDTH,
+ .height = SSD1963_HEIGHT
+};
+
+static struct fb_rgb332 fb_ssd1963_rgb332 = {
+ .mem = fb_ssd1963_mem
+};
+
+struct framebuffer *framebuffer = &fb_ssd1963_framebuffer;
+struct fb_rgb332 *fb_rgb332 = &fb_ssd1963_rgb332;
diff --git a/src/target/firmware/fb/fb_st7558.c b/src/target/firmware/fb/fb_st7558.c
new file mode 100644
index 00000000..fdcd38fb
--- /dev/null
+++ b/src/target/firmware/fb/fb_st7558.c
@@ -0,0 +1,132 @@
+/* Framebuffer implementation - ST1783 LCD driver for C123 */
+/* Based on st7558.c by Harald Welte */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <fb/fb_bw8.h>
+
+#include <i2c.h>
+#include <calypso/clock.h>
+#include <delay.h>
+
+#include <stdio.h>
+
+/* Sitronix ST7558 LCD Driver for OSMOCOM framebuffer interface. */
+/* (c) 2010 Christian Vogel <vogelchr@vogel.cx> */
+/* Based on the initial LCD driver by Harald Welte */
+
+#define CONTROL_RS_CMD
+
+#define ST7558_SLAVE_ADDR 0x3c
+#define ST7558_CMD_ADDR 0x00
+#define ST7558_RAM_ADDR 0x40
+
+#define ST7558_WIDTH 96 /* in pixels */
+#define ST7558_HEIGHT 65
+
+#define I2C_MAX_TRANSFER 16
+
+static uint8_t
+fb_st7558_mem[ST7558_WIDTH * ((ST7558_HEIGHT+7)/8)];
+
+/* setup as initially proposed by Harald in st7558.c */
+static const uint8_t st7558_setup[] = {
+ 0x2e, /* ext. display control, set mirror X, set mirror Y*/
+ 0x21, /* function set, enable extended instruction mode */
+ 0x12, /* bias system BS[2,1,0] = [0,1,0] */
+ 0xc0, /* set V_OP (V_OP6 = 1, V_OP[5:0] = 0) */
+ 0x0b, /* booster stages PC1=1, PC0=1 */
+ 0x20, /* function set, disable extended instruction mode */
+ 0x11, /* V_LCD L/H select, PRS=1 */
+ 0x00, /* NOP */
+ 0x0c, /* normal video mode */
+ 0x40, /* set X address to 0 */
+ 0x80 /* set Y address to 0 */
+};
+
+
+static void
+fb_st7558_init(){
+ calypso_reset_set(RESET_EXT, 0);
+ i2c_init(0,0);
+
+ /* initialize controller */
+ i2c_write(ST7558_SLAVE_ADDR,ST7558_CMD_ADDR,1,
+ st7558_setup,sizeof(st7558_setup));
+}
+
+static void
+fb_st7558_flush(){
+ uint16_t x;
+ int page,chunksize,nbytes;
+ uint8_t *p;
+ uint8_t cmd[2];
+
+ if(fb_bw8->damage_y1 == fb_bw8->damage_y2 ||
+ fb_bw8->damage_x1 == fb_bw8->damage_x2)
+ return; /* nothing to update */
+
+ /* update display in stripes of 8 rows, called "pages" */
+ for(page=fb_bw8->damage_y1 >> 3;page <= fb_bw8->damage_y2>>3;page++){
+ /* base offset in RAM framebuffer */
+ x = fb_bw8->damage_x1;
+ nbytes = fb_bw8->damage_x2 - fb_bw8->damage_x1;
+ p = fb_bw8->mem + (page * framebuffer->width + x);
+
+ /* i2c fifo can only handle a maximum of 16 bytes */
+ while(nbytes){
+ cmd[0]=0x40 | page; /* Set Y address of RAM. */
+ cmd[1]=0x80 | x;
+ chunksize = nbytes > I2C_MAX_TRANSFER ? I2C_MAX_TRANSFER : nbytes;
+
+ i2c_write(ST7558_SLAVE_ADDR,ST7558_CMD_ADDR,1,cmd,sizeof(cmd));
+ i2c_write(ST7558_SLAVE_ADDR,ST7558_RAM_ADDR,1,p,chunksize);
+
+ nbytes -= chunksize;
+ p+=I2C_MAX_TRANSFER;
+ x+=I2C_MAX_TRANSFER;
+ }
+ }
+
+ /* mark current buffer as unmodified! */
+ fb_bw8->damage_x1 = fb_bw8->damage_x2 = 0;
+ fb_bw8->damage_y1 = fb_bw8->damage_y2 = 0;
+}
+
+static struct framebuffer fb_st7558_framebuffer = {
+ .name = "st7558",
+ .init = fb_st7558_init,
+ .clear = fb_bw8_clear,
+ .boxto = fb_bw8_boxto,
+ .lineto = fb_bw8_lineto,
+ .putstr = fb_bw8_putstr,
+ .flush = fb_st7558_flush,
+ .width = ST7558_WIDTH,
+ .height = ST7558_HEIGHT
+};
+
+static struct fb_bw8 fb_st7558_bw8 = {
+ .mem = fb_st7558_mem
+};
+
+struct framebuffer *framebuffer = &fb_st7558_framebuffer;
+struct fb_bw8 *fb_bw8 = &fb_st7558_bw8;
diff --git a/src/target/firmware/fb/fb_td014.c b/src/target/firmware/fb/fb_td014.c
new file mode 100644
index 00000000..c7bde0ca
--- /dev/null
+++ b/src/target/firmware/fb/fb_td014.c
@@ -0,0 +1,150 @@
+/* Framebuffer implementation - Toppoly TD014 LCD driver for Motorola C139/40 */
+/* Based on td014.c by Steve Markgraf and Harald Welte */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ * (C) 2012 by Steve Markgraf <steve@steve-m.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+#include <fb/fb_rgb332.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <delay.h>
+#include <uwire.h>
+#include <calypso/clock.h>
+
+#define TD014_WIDTH 96
+#define TD014_HEIGHT 64
+#define TD014_UWIRE_BITLEN 9
+#define TD014_DEV_ID 0
+
+static uint8_t fb_td014_mem[TD014_WIDTH * TD014_HEIGHT];
+
+enum td014_cmdflag { CMD, DATA, END };
+
+struct td014_cmdlist {
+ enum td014_cmdflag is_cmd:8; /* 1: is a command, 0: is data, 2: end marker! */
+ uint8_t data; /* 8 bit to send to LC display */
+} __attribute__((packed));
+
+static const struct td014_cmdlist
+td014_initdata[] = {
+ { CMD, 0x3f },
+ { DATA, 0x01 },
+ { CMD, 0x20 },
+ { DATA, 0x03 },
+ { CMD, 0x31 },
+ { DATA, 0x03 },
+ { END, 0x00 }, /* MARKER: end of list */
+};
+
+static void
+fb_td014_send_cmdlist(const struct td014_cmdlist *p) {
+ int i=0;
+ while(p->is_cmd != END){
+ uint16_t sendcmd = p->data;
+ if(p->is_cmd == DATA)
+ sendcmd |= 0x0100; /* 9th bit is cmd/data flag */
+ uwire_xfer(TD014_DEV_ID, TD014_UWIRE_BITLEN, &sendcmd, NULL);
+ p++;
+ i++;
+ }
+}
+
+static void
+fb_td014_init(void) {
+ printf("%s: initializing LCD.\n",__FUNCTION__);
+ calypso_reset_set(RESET_EXT, 0);
+ delay_ms(5);
+ uwire_init();
+ delay_ms(5);
+
+ fb_td014_send_cmdlist(td014_initdata);
+}
+
+static void
+fb_td014_flush(void) {
+ int x,y;
+ uint8_t *p;
+ struct td014_cmdlist prepare_disp_write_cmds[] = {
+ { CMD, 0x10 },
+ { DATA, fb_rgb332->damage_x1 },
+ { CMD, 0x11 },
+ { DATA, fb_rgb332->damage_y1 },
+ { CMD, 0x12 },
+ { DATA, fb_rgb332->damage_x2-1 },
+ { CMD, 0x13 },
+ { DATA, fb_rgb332->damage_y2-1 },
+ { CMD, 0x14 },
+ { DATA, fb_rgb332->damage_x1 },
+ { CMD, 0x15 },
+ { DATA, fb_rgb332->damage_y1 },
+ { END, 0x00 }
+ };
+
+ /* If everything's clean, just return */
+ if(fb_rgb332->damage_x1 == fb_rgb332->damage_x2 ||
+ fb_rgb332->damage_y1 == fb_rgb332->damage_y2) {
+ printf("%s: no damage\n",__FUNCTION__);
+ return;
+ }
+
+ fb_td014_send_cmdlist(prepare_disp_write_cmds);
+
+ for(y=fb_rgb332->damage_y1;y<fb_rgb332->damage_y2;y++) {
+ p = & fb_rgb332->mem[y * framebuffer->width]; // start of line
+ p += fb_rgb332->damage_x1; // start of damage area
+
+ for(x=fb_rgb332->damage_x1; x<fb_rgb332->damage_x2; x++) {
+ uint16_t pixel = rgb332_to_565(*p++);
+ uint16_t data = 0x0100 | (pixel >> 8);
+
+ uwire_xfer(TD014_DEV_ID, TD014_UWIRE_BITLEN,
+ &data, NULL);
+
+ data = 0x0100 | (pixel & 0xff);
+ uwire_xfer(TD014_DEV_ID, TD014_UWIRE_BITLEN,
+ &data, NULL);
+ }
+ }
+
+ fb_rgb332->damage_x1 = fb_rgb332->damage_x2 = 0;
+ fb_rgb332->damage_y1 = fb_rgb332->damage_y2 = 0;
+}
+
+static struct framebuffer fb_td014_framebuffer = {
+ .name = "td014",
+ .init = fb_td014_init,
+ .clear = fb_rgb332_clear,
+ .boxto = fb_rgb332_boxto,
+ .lineto = fb_rgb332_lineto,
+ .putstr = fb_rgb332_putstr,
+ .flush = fb_td014_flush,
+ .width = TD014_WIDTH,
+ .height = TD014_HEIGHT
+};
+
+static struct fb_rgb332 fb_td014_rgb332 = {
+ .mem = fb_td014_mem
+};
+
+struct framebuffer *framebuffer = &fb_td014_framebuffer;
+struct fb_rgb332 *fb_rgb332 = &fb_td014_rgb332;
diff --git a/src/target/firmware/fb/font.c b/src/target/firmware/fb/font.c
new file mode 100644
index 00000000..18c1bfe9
--- /dev/null
+++ b/src/target/firmware/fb/font.c
@@ -0,0 +1,59 @@
+/* Font Handling - Utility Functions */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/font.h>
+
+/* what fonts are linked in? */
+extern const struct fb_font font_4x6;
+extern const struct fb_font font_5x8;
+extern const struct fb_font font_helvR08;
+extern const struct fb_font font_helvR14;
+//extern const struct fb_font font_helvR24;
+//extern const struct fb_font font_helvB08;
+extern const struct fb_font font_helvB14;
+// extern const struct fb_font font_helvB24;
+extern const struct fb_font font_c64;
+extern const struct fb_font font_symbols;
+
+const struct fb_font *fb_fonts[]={
+// &font_4x6,
+// &font_5x8,
+ &font_helvR08,
+// &font_helvR14,
+// &font_helvR24,
+// &font_helvB08,
+ &font_helvB14,
+// &font_helvB24,
+ &font_c64,
+ &font_symbols,
+};
+
+const struct fb_char *
+fb_font_get_char(const struct fb_font *fnt,unsigned char c){
+ if(c < fnt->firstchar || c > fnt->lastchar)
+ return NULL;
+ uint16_t offs = fnt->charoffs[c-fnt->firstchar];
+ if(offs == FB_FONT_NOCHAR)
+ return NULL;
+ return (struct fb_char *)(fnt->chardata + offs);
+}
+
diff --git a/src/target/firmware/fb/framebuffer.c b/src/target/firmware/fb/framebuffer.c
new file mode 100644
index 00000000..ab547694
--- /dev/null
+++ b/src/target/firmware/fb/framebuffer.c
@@ -0,0 +1,28 @@
+/* Framebuffer - Utility Functions */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <fb/framebuffer.h>
+
+/* currently everything's inline in framebuffer .h */
+
+
+
diff --git a/src/target/firmware/fb/helvB08.c b/src/target/firmware/fb/helvB08.c
new file mode 100644
index 00000000..97dd92ca
--- /dev/null
+++ b/src/target/firmware/fb/helvB08.c
@@ -0,0 +1,833 @@
+#include <fb/font.h>
+static const uint8_t font_helvB08_data[] = {
+/* --- new character space (32) starting at offset 0x0000 --- */
+ /*0000:*/ 2, 1, 1, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x00, /* ........ */
+/* --- new character exclam (33) starting at offset 0x0006 --- */
+ /*0006:*/ 3, 2, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*000b:*/ 0xc0, /* ##...... */
+ /*000c:*/ 0xc0, /* ##...... */
+ /*000d:*/ 0xc0, /* ##...... */
+ /*000e:*/ 0x80, /* #....... */
+ /*000f:*/ 0x00, /* ........ */
+ /*0010:*/ 0x80, /* #....... */
+ /*0011:*/ 0x80, /* #....... */
+/* --- new character quotedbl (34) starting at offset 0x0012 --- */
+ /*0012:*/ 4, 3, 2, 0, 4, /* width and bbox (w,h,x,y) */
+ /*0017:*/ 0xa0, /* #.#..... */
+ /*0018:*/ 0xa0, /* #.#..... */
+/* --- new character numbersign (35) starting at offset 0x0019 --- */
+ /*0019:*/ 5, 5, 6, -1, 0, /* width and bbox (w,h,x,y) */
+ /*001e:*/ 0x50, /* .#.#.... */
+ /*001f:*/ 0xf8, /* #####... */
+ /*0020:*/ 0x50, /* .#.#.... */
+ /*0021:*/ 0xf8, /* #####... */
+ /*0022:*/ 0xa0, /* #.#..... */
+ /*0023:*/ 0xa0, /* #.#..... */
+/* --- new character dollar (36) starting at offset 0x0024 --- */
+ /*0024:*/ 5, 4, 8, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0029:*/ 0x20, /* ..#..... */
+ /*002a:*/ 0x70, /* .###.... */
+ /*002b:*/ 0xc0, /* ##...... */
+ /*002c:*/ 0xe0, /* ###..... */
+ /*002d:*/ 0x70, /* .###.... */
+ /*002e:*/ 0x30, /* ..##.... */
+ /*002f:*/ 0xe0, /* ###..... */
+ /*0030:*/ 0x40, /* .#...... */
+/* --- new character percent (37) starting at offset 0x0031 --- */
+ /*0031:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0036:*/ 0x68, /* .##.#... */
+ /*0037:*/ 0xb0, /* #.##.... */
+ /*0038:*/ 0xe0, /* ###..... */
+ /*0039:*/ 0x38, /* ..###... */
+ /*003a:*/ 0x68, /* .##.#... */
+ /*003b:*/ 0xb0, /* #.##.... */
+/* --- new character ampersand (38) starting at offset 0x003c --- */
+ /*003c:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0041:*/ 0x70, /* .###.... */
+ /*0042:*/ 0x50, /* .#.#.... */
+ /*0043:*/ 0x60, /* .##..... */
+ /*0044:*/ 0xf8, /* #####... */
+ /*0045:*/ 0xd0, /* ##.#.... */
+ /*0046:*/ 0x68, /* .##.#... */
+/* --- new character quotesingle (39) starting at offset 0x0047 --- */
+ /*0047:*/ 3, 1, 3, 1, 5, /* width and bbox (w,h,x,y) */
+ /*004c:*/ 0x80, /* #....... */
+ /*004d:*/ 0x80, /* #....... */
+ /*004e:*/ 0x80, /* #....... */
+/* --- new character parenleft (40) starting at offset 0x004f --- */
+ /*004f:*/ 3, 2, 8, 0, -2, /* width and bbox (w,h,x,y) */
+ /*0054:*/ 0x40, /* .#...... */
+ /*0055:*/ 0x40, /* .#...... */
+ /*0056:*/ 0x80, /* #....... */
+ /*0057:*/ 0x80, /* #....... */
+ /*0058:*/ 0x80, /* #....... */
+ /*0059:*/ 0x80, /* #....... */
+ /*005a:*/ 0x40, /* .#...... */
+ /*005b:*/ 0x40, /* .#...... */
+/* --- new character parenright (41) starting at offset 0x005c --- */
+ /*005c:*/ 3, 2, 8, 0, -2, /* width and bbox (w,h,x,y) */
+ /*0061:*/ 0x80, /* #....... */
+ /*0062:*/ 0x80, /* #....... */
+ /*0063:*/ 0x40, /* .#...... */
+ /*0064:*/ 0x40, /* .#...... */
+ /*0065:*/ 0x40, /* .#...... */
+ /*0066:*/ 0x40, /* .#...... */
+ /*0067:*/ 0x80, /* #....... */
+ /*0068:*/ 0x80, /* #....... */
+/* --- new character asterisk (42) starting at offset 0x0069 --- */
+ /*0069:*/ 3, 3, 3, 0, 3, /* width and bbox (w,h,x,y) */
+ /*006e:*/ 0x40, /* .#...... */
+ /*006f:*/ 0xe0, /* ###..... */
+ /*0070:*/ 0x40, /* .#...... */
+/* --- new character plus (43) starting at offset 0x0071 --- */
+ /*0071:*/ 5, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0076:*/ 0x20, /* ..#..... */
+ /*0077:*/ 0x20, /* ..#..... */
+ /*0078:*/ 0xf0, /* ####.... */
+ /*0079:*/ 0x20, /* ..#..... */
+ /*007a:*/ 0x20, /* ..#..... */
+/* --- new character comma (44) starting at offset 0x007b --- */
+ /*007b:*/ 2, 2, 3, -1, -1, /* width and bbox (w,h,x,y) */
+ /*0080:*/ 0x40, /* .#...... */
+ /*0081:*/ 0x40, /* .#...... */
+ /*0082:*/ 0x80, /* #....... */
+/* --- new character hyphen (45) starting at offset 0x0083 --- */
+ /*0083:*/ 4, 3, 1, 0, 2, /* width and bbox (w,h,x,y) */
+ /*0088:*/ 0xe0, /* ###..... */
+/* --- new character period (46) starting at offset 0x0089 --- */
+ /*0089:*/ 2, 1, 2, 0, 0, /* width and bbox (w,h,x,y) */
+ /*008e:*/ 0x80, /* #....... */
+ /*008f:*/ 0x80, /* #....... */
+/* --- new character slash (47) starting at offset 0x0090 --- */
+ /*0090:*/ 3, 3, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0095:*/ 0x20, /* ..#..... */
+ /*0096:*/ 0x20, /* ..#..... */
+ /*0097:*/ 0x40, /* .#...... */
+ /*0098:*/ 0x40, /* .#...... */
+ /*0099:*/ 0x80, /* #....... */
+ /*009a:*/ 0x80, /* #....... */
+/* --- new character zero (48) starting at offset 0x009b --- */
+ /*009b:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00a0:*/ 0x60, /* .##..... */
+ /*00a1:*/ 0xd0, /* ##.#.... */
+ /*00a2:*/ 0xd0, /* ##.#.... */
+ /*00a3:*/ 0xd0, /* ##.#.... */
+ /*00a4:*/ 0xd0, /* ##.#.... */
+ /*00a5:*/ 0x60, /* .##..... */
+/* --- new character one (49) starting at offset 0x00a6 --- */
+ /*00a6:*/ 5, 3, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00ab:*/ 0x20, /* ..#..... */
+ /*00ac:*/ 0xe0, /* ###..... */
+ /*00ad:*/ 0x60, /* .##..... */
+ /*00ae:*/ 0x60, /* .##..... */
+ /*00af:*/ 0x60, /* .##..... */
+ /*00b0:*/ 0x60, /* .##..... */
+/* --- new character two (50) starting at offset 0x00b1 --- */
+ /*00b1:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00b6:*/ 0x60, /* .##..... */
+ /*00b7:*/ 0xb0, /* #.##.... */
+ /*00b8:*/ 0x30, /* ..##.... */
+ /*00b9:*/ 0x60, /* .##..... */
+ /*00ba:*/ 0xc0, /* ##...... */
+ /*00bb:*/ 0xf0, /* ####.... */
+/* --- new character three (51) starting at offset 0x00bc --- */
+ /*00bc:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00c1:*/ 0x60, /* .##..... */
+ /*00c2:*/ 0xb0, /* #.##.... */
+ /*00c3:*/ 0x60, /* .##..... */
+ /*00c4:*/ 0x30, /* ..##.... */
+ /*00c5:*/ 0xb0, /* #.##.... */
+ /*00c6:*/ 0x60, /* .##..... */
+/* --- new character four (52) starting at offset 0x00c7 --- */
+ /*00c7:*/ 5, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00cc:*/ 0x30, /* ..##.... */
+ /*00cd:*/ 0x50, /* .#.#.... */
+ /*00ce:*/ 0xd0, /* ##.#.... */
+ /*00cf:*/ 0xf8, /* #####... */
+ /*00d0:*/ 0x30, /* ..##.... */
+ /*00d1:*/ 0x30, /* ..##.... */
+/* --- new character five (53) starting at offset 0x00d2 --- */
+ /*00d2:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00d7:*/ 0x70, /* .###.... */
+ /*00d8:*/ 0xc0, /* ##...... */
+ /*00d9:*/ 0xe0, /* ###..... */
+ /*00da:*/ 0x30, /* ..##.... */
+ /*00db:*/ 0xb0, /* #.##.... */
+ /*00dc:*/ 0x60, /* .##..... */
+/* --- new character six (54) starting at offset 0x00dd --- */
+ /*00dd:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00e2:*/ 0x70, /* .###.... */
+ /*00e3:*/ 0xc0, /* ##...... */
+ /*00e4:*/ 0xe0, /* ###..... */
+ /*00e5:*/ 0xd0, /* ##.#.... */
+ /*00e6:*/ 0xd0, /* ##.#.... */
+ /*00e7:*/ 0x60, /* .##..... */
+/* --- new character seven (55) starting at offset 0x00e8 --- */
+ /*00e8:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00ed:*/ 0xf0, /* ####.... */
+ /*00ee:*/ 0x30, /* ..##.... */
+ /*00ef:*/ 0x30, /* ..##.... */
+ /*00f0:*/ 0x60, /* .##..... */
+ /*00f1:*/ 0x40, /* .#...... */
+ /*00f2:*/ 0xc0, /* ##...... */
+/* --- new character eight (56) starting at offset 0x00f3 --- */
+ /*00f3:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00f8:*/ 0x60, /* .##..... */
+ /*00f9:*/ 0xd0, /* ##.#.... */
+ /*00fa:*/ 0x60, /* .##..... */
+ /*00fb:*/ 0xd0, /* ##.#.... */
+ /*00fc:*/ 0xd0, /* ##.#.... */
+ /*00fd:*/ 0x60, /* .##..... */
+/* --- new character nine (57) starting at offset 0x00fe --- */
+ /*00fe:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0103:*/ 0x60, /* .##..... */
+ /*0104:*/ 0xb0, /* #.##.... */
+ /*0105:*/ 0xb0, /* #.##.... */
+ /*0106:*/ 0x70, /* .###.... */
+ /*0107:*/ 0x30, /* ..##.... */
+ /*0108:*/ 0xe0, /* ###..... */
+/* --- new character colon (58) starting at offset 0x0109 --- */
+ /*0109:*/ 2, 1, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*010e:*/ 0x80, /* #....... */
+ /*010f:*/ 0x80, /* #....... */
+ /*0110:*/ 0x00, /* ........ */
+ /*0111:*/ 0x80, /* #....... */
+ /*0112:*/ 0x80, /* #....... */
+/* --- new character semicolon (59) starting at offset 0x0113 --- */
+ /*0113:*/ 2, 2, 6, -1, -1, /* width and bbox (w,h,x,y) */
+ /*0118:*/ 0x40, /* .#...... */
+ /*0119:*/ 0x40, /* .#...... */
+ /*011a:*/ 0x00, /* ........ */
+ /*011b:*/ 0x40, /* .#...... */
+ /*011c:*/ 0x40, /* .#...... */
+ /*011d:*/ 0x80, /* #....... */
+/* --- new character less (60) starting at offset 0x011e --- */
+ /*011e:*/ 4, 3, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0123:*/ 0x20, /* ..#..... */
+ /*0124:*/ 0x40, /* .#...... */
+ /*0125:*/ 0x80, /* #....... */
+ /*0126:*/ 0x40, /* .#...... */
+ /*0127:*/ 0x20, /* ..#..... */
+/* --- new character equal (61) starting at offset 0x0128 --- */
+ /*0128:*/ 5, 4, 3, 0, 1, /* width and bbox (w,h,x,y) */
+ /*012d:*/ 0xf0, /* ####.... */
+ /*012e:*/ 0x00, /* ........ */
+ /*012f:*/ 0xf0, /* ####.... */
+/* --- new character greater (62) starting at offset 0x0130 --- */
+ /*0130:*/ 4, 3, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0135:*/ 0x80, /* #....... */
+ /*0136:*/ 0x40, /* .#...... */
+ /*0137:*/ 0x20, /* ..#..... */
+ /*0138:*/ 0x40, /* .#...... */
+ /*0139:*/ 0x80, /* #....... */
+/* --- new character question (63) starting at offset 0x013a --- */
+ /*013a:*/ 5, 4, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*013f:*/ 0xe0, /* ###..... */
+ /*0140:*/ 0x30, /* ..##.... */
+ /*0141:*/ 0x60, /* .##..... */
+ /*0142:*/ 0x40, /* .#...... */
+ /*0143:*/ 0x00, /* ........ */
+ /*0144:*/ 0x40, /* .#...... */
+ /*0145:*/ 0x40, /* .#...... */
+/* --- new character at (64) starting at offset 0x0146 --- */
+ /*0146:*/ 9, 8, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*014b:*/ 0x7e, /* .######. */
+ /*014c:*/ 0xc3, /* ##....## */
+ /*014d:*/ 0x99, /* #..##..# */
+ /*014e:*/ 0xa9, /* #.#.#..# */
+ /*014f:*/ 0x99, /* #..##..# */
+ /*0150:*/ 0xce, /* ##..###. */
+ /*0151:*/ 0x60, /* .##..... */
+/* --- new character A (65) starting at offset 0x0152 --- */
+ /*0152:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0157:*/ 0x70, /* .###.... */
+ /*0158:*/ 0xd8, /* ##.##... */
+ /*0159:*/ 0xd8, /* ##.##... */
+ /*015a:*/ 0xf8, /* #####... */
+ /*015b:*/ 0xd8, /* ##.##... */
+ /*015c:*/ 0xd8, /* ##.##... */
+/* --- new character B (66) starting at offset 0x015d --- */
+ /*015d:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0162:*/ 0xf0, /* ####.... */
+ /*0163:*/ 0xd8, /* ##.##... */
+ /*0164:*/ 0xf0, /* ####.... */
+ /*0165:*/ 0xd8, /* ##.##... */
+ /*0166:*/ 0xd8, /* ##.##... */
+ /*0167:*/ 0xf0, /* ####.... */
+/* --- new character C (67) starting at offset 0x0168 --- */
+ /*0168:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*016d:*/ 0x78, /* .####... */
+ /*016e:*/ 0xc8, /* ##..#... */
+ /*016f:*/ 0xc0, /* ##...... */
+ /*0170:*/ 0xc0, /* ##...... */
+ /*0171:*/ 0xc8, /* ##..#... */
+ /*0172:*/ 0x78, /* .####... */
+/* --- new character D (68) starting at offset 0x0173 --- */
+ /*0173:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0178:*/ 0xf0, /* ####.... */
+ /*0179:*/ 0xd8, /* ##.##... */
+ /*017a:*/ 0xd8, /* ##.##... */
+ /*017b:*/ 0xd8, /* ##.##... */
+ /*017c:*/ 0xd8, /* ##.##... */
+ /*017d:*/ 0xf0, /* ####.... */
+/* --- new character E (69) starting at offset 0x017e --- */
+ /*017e:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0183:*/ 0xf0, /* ####.... */
+ /*0184:*/ 0xc0, /* ##...... */
+ /*0185:*/ 0xf0, /* ####.... */
+ /*0186:*/ 0xc0, /* ##...... */
+ /*0187:*/ 0xc0, /* ##...... */
+ /*0188:*/ 0xf0, /* ####.... */
+/* --- new character F (70) starting at offset 0x0189 --- */
+ /*0189:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*018e:*/ 0xf0, /* ####.... */
+ /*018f:*/ 0xc0, /* ##...... */
+ /*0190:*/ 0xf0, /* ####.... */
+ /*0191:*/ 0xc0, /* ##...... */
+ /*0192:*/ 0xc0, /* ##...... */
+ /*0193:*/ 0xc0, /* ##...... */
+/* --- new character G (71) starting at offset 0x0194 --- */
+ /*0194:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0199:*/ 0x78, /* .####... */
+ /*019a:*/ 0xc8, /* ##..#... */
+ /*019b:*/ 0xc0, /* ##...... */
+ /*019c:*/ 0xd8, /* ##.##... */
+ /*019d:*/ 0xc8, /* ##..#... */
+ /*019e:*/ 0x78, /* .####... */
+/* --- new character H (72) starting at offset 0x019f --- */
+ /*019f:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01a4:*/ 0xd8, /* ##.##... */
+ /*01a5:*/ 0xd8, /* ##.##... */
+ /*01a6:*/ 0xf8, /* #####... */
+ /*01a7:*/ 0xd8, /* ##.##... */
+ /*01a8:*/ 0xd8, /* ##.##... */
+ /*01a9:*/ 0xd8, /* ##.##... */
+/* --- new character I (73) starting at offset 0x01aa --- */
+ /*01aa:*/ 2, 1, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01af:*/ 0x80, /* #....... */
+ /*01b0:*/ 0x80, /* #....... */
+ /*01b1:*/ 0x80, /* #....... */
+ /*01b2:*/ 0x80, /* #....... */
+ /*01b3:*/ 0x80, /* #....... */
+ /*01b4:*/ 0x80, /* #....... */
+/* --- new character J (74) starting at offset 0x01b5 --- */
+ /*01b5:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01ba:*/ 0x30, /* ..##.... */
+ /*01bb:*/ 0x30, /* ..##.... */
+ /*01bc:*/ 0x30, /* ..##.... */
+ /*01bd:*/ 0x30, /* ..##.... */
+ /*01be:*/ 0xb0, /* #.##.... */
+ /*01bf:*/ 0x60, /* .##..... */
+/* --- new character K (75) starting at offset 0x01c0 --- */
+ /*01c0:*/ 6, 6, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01c5:*/ 0xd8, /* ##.##... */
+ /*01c6:*/ 0xd0, /* ##.#.... */
+ /*01c7:*/ 0xe0, /* ###..... */
+ /*01c8:*/ 0xf0, /* ####.... */
+ /*01c9:*/ 0xd8, /* ##.##... */
+ /*01ca:*/ 0xcc, /* ##..##.. */
+/* --- new character L (76) starting at offset 0x01cb --- */
+ /*01cb:*/ 5, 4, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01d0:*/ 0xc0, /* ##...... */
+ /*01d1:*/ 0xc0, /* ##...... */
+ /*01d2:*/ 0xc0, /* ##...... */
+ /*01d3:*/ 0xc0, /* ##...... */
+ /*01d4:*/ 0xc0, /* ##...... */
+ /*01d5:*/ 0xf0, /* ####.... */
+/* --- new character M (77) starting at offset 0x01d6 --- */
+ /*01d6:*/ 8, 7, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01db:*/ 0xc6, /* ##...##. */
+ /*01dc:*/ 0xc6, /* ##...##. */
+ /*01dd:*/ 0xee, /* ###.###. */
+ /*01de:*/ 0xfe, /* #######. */
+ /*01df:*/ 0xd6, /* ##.#.##. */
+ /*01e0:*/ 0xd6, /* ##.#.##. */
+/* --- new character N (78) starting at offset 0x01e1 --- */
+ /*01e1:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01e6:*/ 0xc8, /* ##..#... */
+ /*01e7:*/ 0xc8, /* ##..#... */
+ /*01e8:*/ 0xe8, /* ###.#... */
+ /*01e9:*/ 0xf8, /* #####... */
+ /*01ea:*/ 0xd8, /* ##.##... */
+ /*01eb:*/ 0xc8, /* ##..#... */
+/* --- new character O (79) starting at offset 0x01ec --- */
+ /*01ec:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01f1:*/ 0x70, /* .###.... */
+ /*01f2:*/ 0xd8, /* ##.##... */
+ /*01f3:*/ 0xc8, /* ##..#... */
+ /*01f4:*/ 0xc8, /* ##..#... */
+ /*01f5:*/ 0xd8, /* ##.##... */
+ /*01f6:*/ 0x70, /* .###.... */
+/* --- new character P (80) starting at offset 0x01f7 --- */
+ /*01f7:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01fc:*/ 0xf0, /* ####.... */
+ /*01fd:*/ 0xd8, /* ##.##... */
+ /*01fe:*/ 0xd8, /* ##.##... */
+ /*01ff:*/ 0xf0, /* ####.... */
+ /*0200:*/ 0xc0, /* ##...... */
+ /*0201:*/ 0xc0, /* ##...... */
+/* --- new character Q (81) starting at offset 0x0202 --- */
+ /*0202:*/ 6, 6, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0207:*/ 0x70, /* .###.... */
+ /*0208:*/ 0xd8, /* ##.##... */
+ /*0209:*/ 0xc8, /* ##..#... */
+ /*020a:*/ 0xc8, /* ##..#... */
+ /*020b:*/ 0xd8, /* ##.##... */
+ /*020c:*/ 0x78, /* .####... */
+ /*020d:*/ 0x04, /* .....#.. */
+/* --- new character R (82) starting at offset 0x020e --- */
+ /*020e:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0213:*/ 0xf0, /* ####.... */
+ /*0214:*/ 0xd8, /* ##.##... */
+ /*0215:*/ 0xd8, /* ##.##... */
+ /*0216:*/ 0xf0, /* ####.... */
+ /*0217:*/ 0xd8, /* ##.##... */
+ /*0218:*/ 0xd8, /* ##.##... */
+/* --- new character S (83) starting at offset 0x0219 --- */
+ /*0219:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*021e:*/ 0x78, /* .####... */
+ /*021f:*/ 0xc0, /* ##...... */
+ /*0220:*/ 0xf0, /* ####.... */
+ /*0221:*/ 0x38, /* ..###... */
+ /*0222:*/ 0xd8, /* ##.##... */
+ /*0223:*/ 0x70, /* .###.... */
+/* --- new character T (84) starting at offset 0x0224 --- */
+ /*0224:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0229:*/ 0xf8, /* #####... */
+ /*022a:*/ 0x60, /* .##..... */
+ /*022b:*/ 0x60, /* .##..... */
+ /*022c:*/ 0x60, /* .##..... */
+ /*022d:*/ 0x60, /* .##..... */
+ /*022e:*/ 0x60, /* .##..... */
+/* --- new character U (85) starting at offset 0x022f --- */
+ /*022f:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0234:*/ 0xd8, /* ##.##... */
+ /*0235:*/ 0xd8, /* ##.##... */
+ /*0236:*/ 0xd8, /* ##.##... */
+ /*0237:*/ 0xd8, /* ##.##... */
+ /*0238:*/ 0xd8, /* ##.##... */
+ /*0239:*/ 0x70, /* .###.... */
+/* --- new character V (86) starting at offset 0x023a --- */
+ /*023a:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*023f:*/ 0xe8, /* ###.#... */
+ /*0240:*/ 0x68, /* .##.#... */
+ /*0241:*/ 0x68, /* .##.#... */
+ /*0242:*/ 0x68, /* .##.#... */
+ /*0243:*/ 0x70, /* .###.... */
+ /*0244:*/ 0x20, /* ..#..... */
+/* --- new character W (87) starting at offset 0x0245 --- */
+ /*0245:*/ 9, 8, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*024a:*/ 0xdb, /* ##.##.## */
+ /*024b:*/ 0xdb, /* ##.##.## */
+ /*024c:*/ 0xda, /* ##.##.#. */
+ /*024d:*/ 0xda, /* ##.##.#. */
+ /*024e:*/ 0x6c, /* .##.##.. */
+ /*024f:*/ 0x6c, /* .##.##.. */
+/* --- new character X (88) starting at offset 0x0250 --- */
+ /*0250:*/ 6, 5, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0255:*/ 0xd8, /* ##.##... */
+ /*0256:*/ 0xd8, /* ##.##... */
+ /*0257:*/ 0x70, /* .###.... */
+ /*0258:*/ 0x70, /* .###.... */
+ /*0259:*/ 0xd8, /* ##.##... */
+ /*025a:*/ 0xd8, /* ##.##... */
+/* --- new character Y (89) starting at offset 0x025b --- */
+ /*025b:*/ 7, 6, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0260:*/ 0xec, /* ###.##.. */
+ /*0261:*/ 0x68, /* .##.#... */
+ /*0262:*/ 0x68, /* .##.#... */
+ /*0263:*/ 0x78, /* .####... */
+ /*0264:*/ 0x30, /* ..##.... */
+ /*0265:*/ 0x30, /* ..##.... */
+/* --- new character Z (90) starting at offset 0x0266 --- */
+ /*0266:*/ 6, 6, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*026b:*/ 0xfc, /* ######.. */
+ /*026c:*/ 0x38, /* ..###... */
+ /*026d:*/ 0x30, /* ..##.... */
+ /*026e:*/ 0x60, /* .##..... */
+ /*026f:*/ 0xe0, /* ###..... */
+ /*0270:*/ 0xf8, /* #####... */
+/* --- new character bracketleft (91) starting at offset 0x0271 --- */
+ /*0271:*/ 3, 2, 8, 0, -2, /* width and bbox (w,h,x,y) */
+ /*0276:*/ 0xc0, /* ##...... */
+ /*0277:*/ 0x80, /* #....... */
+ /*0278:*/ 0x80, /* #....... */
+ /*0279:*/ 0x80, /* #....... */
+ /*027a:*/ 0x80, /* #....... */
+ /*027b:*/ 0x80, /* #....... */
+ /*027c:*/ 0x80, /* #....... */
+ /*027d:*/ 0xc0, /* ##...... */
+/* --- new character backslash (92) starting at offset 0x027e --- */
+ /*027e:*/ 3, 3, 6, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0283:*/ 0x80, /* #....... */
+ /*0284:*/ 0x80, /* #....... */
+ /*0285:*/ 0x40, /* .#...... */
+ /*0286:*/ 0x40, /* .#...... */
+ /*0287:*/ 0x20, /* ..#..... */
+ /*0288:*/ 0x20, /* ..#..... */
+/* --- new character bracketright (93) starting at offset 0x0289 --- */
+ /*0289:*/ 3, 2, 8, 0, -2, /* width and bbox (w,h,x,y) */
+ /*028e:*/ 0xc0, /* ##...... */
+ /*028f:*/ 0x40, /* .#...... */
+ /*0290:*/ 0x40, /* .#...... */
+ /*0291:*/ 0x40, /* .#...... */
+ /*0292:*/ 0x40, /* .#...... */
+ /*0293:*/ 0x40, /* .#...... */
+ /*0294:*/ 0x40, /* .#...... */
+ /*0295:*/ 0xc0, /* ##...... */
+/* --- new character asciicircum (94) starting at offset 0x0296 --- */
+ /*0296:*/ 4, 4, 3, 0, 3, /* width and bbox (w,h,x,y) */
+ /*029b:*/ 0x60, /* .##..... */
+ /*029c:*/ 0x60, /* .##..... */
+ /*029d:*/ 0x90, /* #..#.... */
+/* --- new character underscore (95) starting at offset 0x029e --- */
+ /*029e:*/ 5, 5, 1, 0, -1, /* width and bbox (w,h,x,y) */
+ /*02a3:*/ 0xf8, /* #####... */
+/* --- new character grave (96) starting at offset 0x02a4 --- */
+ /*02a4:*/ 3, 2, 2, 0, 6, /* width and bbox (w,h,x,y) */
+ /*02a9:*/ 0x80, /* #....... */
+ /*02aa:*/ 0x40, /* .#...... */
+/* --- new character a (97) starting at offset 0x02ab --- */
+ /*02ab:*/ 5, 5, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02b0:*/ 0xe0, /* ###..... */
+ /*02b1:*/ 0x30, /* ..##.... */
+ /*02b2:*/ 0xf0, /* ####.... */
+ /*02b3:*/ 0xb0, /* #.##.... */
+ /*02b4:*/ 0xd8, /* ##.##... */
+/* --- new character b (98) starting at offset 0x02b5 --- */
+ /*02b5:*/ 5, 4, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02ba:*/ 0xc0, /* ##...... */
+ /*02bb:*/ 0xc0, /* ##...... */
+ /*02bc:*/ 0xe0, /* ###..... */
+ /*02bd:*/ 0xd0, /* ##.#.... */
+ /*02be:*/ 0xd0, /* ##.#.... */
+ /*02bf:*/ 0xd0, /* ##.#.... */
+ /*02c0:*/ 0xe0, /* ###..... */
+/* --- new character c (99) starting at offset 0x02c1 --- */
+ /*02c1:*/ 4, 3, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02c6:*/ 0x60, /* .##..... */
+ /*02c7:*/ 0xc0, /* ##...... */
+ /*02c8:*/ 0xc0, /* ##...... */
+ /*02c9:*/ 0xc0, /* ##...... */
+ /*02ca:*/ 0x60, /* .##..... */
+/* --- new character d (100) starting at offset 0x02cb --- */
+ /*02cb:*/ 5, 4, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02d0:*/ 0x30, /* ..##.... */
+ /*02d1:*/ 0x30, /* ..##.... */
+ /*02d2:*/ 0x70, /* .###.... */
+ /*02d3:*/ 0xb0, /* #.##.... */
+ /*02d4:*/ 0xb0, /* #.##.... */
+ /*02d5:*/ 0xb0, /* #.##.... */
+ /*02d6:*/ 0x70, /* .###.... */
+/* --- new character e (101) starting at offset 0x02d7 --- */
+ /*02d7:*/ 5, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02dc:*/ 0x60, /* .##..... */
+ /*02dd:*/ 0xd0, /* ##.#.... */
+ /*02de:*/ 0xf0, /* ####.... */
+ /*02df:*/ 0xc0, /* ##...... */
+ /*02e0:*/ 0x60, /* .##..... */
+/* --- new character f (102) starting at offset 0x02e1 --- */
+ /*02e1:*/ 3, 4, 7, -1, 0, /* width and bbox (w,h,x,y) */
+ /*02e6:*/ 0x30, /* ..##.... */
+ /*02e7:*/ 0x60, /* .##..... */
+ /*02e8:*/ 0xf0, /* ####.... */
+ /*02e9:*/ 0x60, /* .##..... */
+ /*02ea:*/ 0x60, /* .##..... */
+ /*02eb:*/ 0x60, /* .##..... */
+ /*02ec:*/ 0x60, /* .##..... */
+/* --- new character g (103) starting at offset 0x02ed --- */
+ /*02ed:*/ 5, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*02f2:*/ 0xd0, /* ##.#.... */
+ /*02f3:*/ 0xb0, /* #.##.... */
+ /*02f4:*/ 0xb0, /* #.##.... */
+ /*02f5:*/ 0xf0, /* ####.... */
+ /*02f6:*/ 0x30, /* ..##.... */
+ /*02f7:*/ 0xe0, /* ###..... */
+/* --- new character h (104) starting at offset 0x02f8 --- */
+ /*02f8:*/ 5, 4, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02fd:*/ 0xc0, /* ##...... */
+ /*02fe:*/ 0xc0, /* ##...... */
+ /*02ff:*/ 0xe0, /* ###..... */
+ /*0300:*/ 0xd0, /* ##.#.... */
+ /*0301:*/ 0xd0, /* ##.#.... */
+ /*0302:*/ 0xd0, /* ##.#.... */
+ /*0303:*/ 0xd0, /* ##.#.... */
+/* --- new character i (105) starting at offset 0x0304 --- */
+ /*0304:*/ 2, 1, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0309:*/ 0x80, /* #....... */
+ /*030a:*/ 0x00, /* ........ */
+ /*030b:*/ 0x80, /* #....... */
+ /*030c:*/ 0x80, /* #....... */
+ /*030d:*/ 0x80, /* #....... */
+ /*030e:*/ 0x80, /* #....... */
+ /*030f:*/ 0x80, /* #....... */
+/* --- new character j (106) starting at offset 0x0310 --- */
+ /*0310:*/ 2, 2, 8, -1, -1, /* width and bbox (w,h,x,y) */
+ /*0315:*/ 0x40, /* .#...... */
+ /*0316:*/ 0x00, /* ........ */
+ /*0317:*/ 0x40, /* .#...... */
+ /*0318:*/ 0x40, /* .#...... */
+ /*0319:*/ 0x40, /* .#...... */
+ /*031a:*/ 0x40, /* .#...... */
+ /*031b:*/ 0x40, /* .#...... */
+ /*031c:*/ 0x80, /* #....... */
+/* --- new character k (107) starting at offset 0x031d --- */
+ /*031d:*/ 5, 4, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0322:*/ 0xc0, /* ##...... */
+ /*0323:*/ 0xc0, /* ##...... */
+ /*0324:*/ 0xd0, /* ##.#.... */
+ /*0325:*/ 0xd0, /* ##.#.... */
+ /*0326:*/ 0xe0, /* ###..... */
+ /*0327:*/ 0xd0, /* ##.#.... */
+ /*0328:*/ 0xd0, /* ##.#.... */
+/* --- new character l (108) starting at offset 0x0329 --- */
+ /*0329:*/ 2, 1, 7, 0, 0, /* width and bbox (w,h,x,y) */
+ /*032e:*/ 0x80, /* #....... */
+ /*032f:*/ 0x80, /* #....... */
+ /*0330:*/ 0x80, /* #....... */
+ /*0331:*/ 0x80, /* #....... */
+ /*0332:*/ 0x80, /* #....... */
+ /*0333:*/ 0x80, /* #....... */
+ /*0334:*/ 0x80, /* #....... */
+/* --- new character m (109) starting at offset 0x0335 --- */
+ /*0335:*/ 7, 6, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*033a:*/ 0xe8, /* ###.#... */
+ /*033b:*/ 0xd4, /* ##.#.#.. */
+ /*033c:*/ 0xd4, /* ##.#.#.. */
+ /*033d:*/ 0xd4, /* ##.#.#.. */
+ /*033e:*/ 0xd4, /* ##.#.#.. */
+/* --- new character n (110) starting at offset 0x033f --- */
+ /*033f:*/ 5, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0344:*/ 0xe0, /* ###..... */
+ /*0345:*/ 0xd0, /* ##.#.... */
+ /*0346:*/ 0xd0, /* ##.#.... */
+ /*0347:*/ 0xd0, /* ##.#.... */
+ /*0348:*/ 0xd0, /* ##.#.... */
+/* --- new character o (111) starting at offset 0x0349 --- */
+ /*0349:*/ 5, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*034e:*/ 0x60, /* .##..... */
+ /*034f:*/ 0xd0, /* ##.#.... */
+ /*0350:*/ 0xd0, /* ##.#.... */
+ /*0351:*/ 0xd0, /* ##.#.... */
+ /*0352:*/ 0x60, /* .##..... */
+/* --- new character p (112) starting at offset 0x0353 --- */
+ /*0353:*/ 5, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0358:*/ 0xe0, /* ###..... */
+ /*0359:*/ 0xd0, /* ##.#.... */
+ /*035a:*/ 0xd0, /* ##.#.... */
+ /*035b:*/ 0xd0, /* ##.#.... */
+ /*035c:*/ 0xe0, /* ###..... */
+ /*035d:*/ 0xc0, /* ##...... */
+/* --- new character q (113) starting at offset 0x035e --- */
+ /*035e:*/ 5, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0363:*/ 0x70, /* .###.... */
+ /*0364:*/ 0xb0, /* #.##.... */
+ /*0365:*/ 0xb0, /* #.##.... */
+ /*0366:*/ 0xb0, /* #.##.... */
+ /*0367:*/ 0x70, /* .###.... */
+ /*0368:*/ 0x30, /* ..##.... */
+/* --- new character r (114) starting at offset 0x0369 --- */
+ /*0369:*/ 3, 3, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*036e:*/ 0xa0, /* #.#..... */
+ /*036f:*/ 0xe0, /* ###..... */
+ /*0370:*/ 0xc0, /* ##...... */
+ /*0371:*/ 0xc0, /* ##...... */
+ /*0372:*/ 0xc0, /* ##...... */
+/* --- new character s (115) starting at offset 0x0373 --- */
+ /*0373:*/ 5, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0378:*/ 0x70, /* .###.... */
+ /*0379:*/ 0xc0, /* ##...... */
+ /*037a:*/ 0xf0, /* ####.... */
+ /*037b:*/ 0x30, /* ..##.... */
+ /*037c:*/ 0xe0, /* ###..... */
+/* --- new character t (116) starting at offset 0x037d --- */
+ /*037d:*/ 3, 4, 7, -1, 0, /* width and bbox (w,h,x,y) */
+ /*0382:*/ 0x20, /* ..#..... */
+ /*0383:*/ 0x60, /* .##..... */
+ /*0384:*/ 0xf0, /* ####.... */
+ /*0385:*/ 0x60, /* .##..... */
+ /*0386:*/ 0x60, /* .##..... */
+ /*0387:*/ 0x60, /* .##..... */
+ /*0388:*/ 0x30, /* ..##.... */
+/* --- new character u (117) starting at offset 0x0389 --- */
+ /*0389:*/ 5, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*038e:*/ 0xd0, /* ##.#.... */
+ /*038f:*/ 0xd0, /* ##.#.... */
+ /*0390:*/ 0xd0, /* ##.#.... */
+ /*0391:*/ 0xf0, /* ####.... */
+ /*0392:*/ 0x50, /* .#.#.... */
+/* --- new character v (118) starting at offset 0x0393 --- */
+ /*0393:*/ 5, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0398:*/ 0xd0, /* ##.#.... */
+ /*0399:*/ 0xd0, /* ##.#.... */
+ /*039a:*/ 0xd0, /* ##.#.... */
+ /*039b:*/ 0x60, /* .##..... */
+ /*039c:*/ 0x40, /* .#...... */
+/* --- new character w (119) starting at offset 0x039d --- */
+ /*039d:*/ 6, 5, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03a2:*/ 0xa8, /* #.#.#... */
+ /*03a3:*/ 0xa8, /* #.#.#... */
+ /*03a4:*/ 0xf8, /* #####... */
+ /*03a5:*/ 0xf8, /* #####... */
+ /*03a6:*/ 0x48, /* .#..#... */
+/* --- new character x (120) starting at offset 0x03a7 --- */
+ /*03a7:*/ 6, 5, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03ac:*/ 0xd8, /* ##.##... */
+ /*03ad:*/ 0xd8, /* ##.##... */
+ /*03ae:*/ 0x70, /* .###.... */
+ /*03af:*/ 0xd8, /* ##.##... */
+ /*03b0:*/ 0xd8, /* ##.##... */
+/* --- new character y (121) starting at offset 0x03b1 --- */
+ /*03b1:*/ 5, 4, 6, 0, -1, /* width and bbox (w,h,x,y) */
+ /*03b6:*/ 0xd0, /* ##.#.... */
+ /*03b7:*/ 0xd0, /* ##.#.... */
+ /*03b8:*/ 0xd0, /* ##.#.... */
+ /*03b9:*/ 0x70, /* .###.... */
+ /*03ba:*/ 0x60, /* .##..... */
+ /*03bb:*/ 0x60, /* .##..... */
+/* --- new character z (122) starting at offset 0x03bc --- */
+ /*03bc:*/ 5, 4, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03c1:*/ 0xf0, /* ####.... */
+ /*03c2:*/ 0x30, /* ..##.... */
+ /*03c3:*/ 0x60, /* .##..... */
+ /*03c4:*/ 0xc0, /* ##...... */
+ /*03c5:*/ 0xf0, /* ####.... */
+/* --- new character braceleft (123) starting at offset 0x03c6 --- */
+ /*03c6:*/ 4, 3, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*03cb:*/ 0x20, /* ..#..... */
+ /*03cc:*/ 0x40, /* .#...... */
+ /*03cd:*/ 0x40, /* .#...... */
+ /*03ce:*/ 0x80, /* #....... */
+ /*03cf:*/ 0x40, /* .#...... */
+ /*03d0:*/ 0x40, /* .#...... */
+ /*03d1:*/ 0x20, /* ..#..... */
+/* --- new character bar (124) starting at offset 0x03d2 --- */
+ /*03d2:*/ 2, 1, 7, 1, -1, /* width and bbox (w,h,x,y) */
+ /*03d7:*/ 0x80, /* #....... */
+ /*03d8:*/ 0x80, /* #....... */
+ /*03d9:*/ 0x80, /* #....... */
+ /*03da:*/ 0x80, /* #....... */
+ /*03db:*/ 0x80, /* #....... */
+ /*03dc:*/ 0x80, /* #....... */
+ /*03dd:*/ 0x80, /* #....... */
+/* --- new character braceright (125) starting at offset 0x03de --- */
+ /*03de:*/ 4, 3, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*03e3:*/ 0x80, /* #....... */
+ /*03e4:*/ 0x40, /* .#...... */
+ /*03e5:*/ 0x40, /* .#...... */
+ /*03e6:*/ 0x20, /* ..#..... */
+ /*03e7:*/ 0x40, /* .#...... */
+ /*03e8:*/ 0x40, /* .#...... */
+ /*03e9:*/ 0x80, /* #....... */
+/* --- new character asciitilde (126) starting at offset 0x03ea --- */
+ /*03ea:*/ 5, 5, 2, 0, 2, /* width and bbox (w,h,x,y) */
+ /*03ef:*/ 0x58, /* .#.##... */
+ /*03f0:*/ 0xb0, /* #.##.... */
+};
+static const uint16_t font_helvB08_offsets[] = {
+0x0000 /* space */,
+ 0x0006 /* exclam */,
+ 0x0012 /* quotedbl */,
+ 0x0019 /* numbersign */,
+ 0x0024 /* dollar */,
+ 0x0031 /* percent */,
+ 0x003c /* ampersand */,
+ 0x0047 /* quotesingle */,
+ 0x004f /* parenleft */,
+ 0x005c /* parenright */,
+ 0x0069 /* asterisk */,
+ 0x0071 /* plus */,
+ 0x007b /* comma */,
+ 0x0083 /* hyphen */,
+ 0x0089 /* period */,
+ 0x0090 /* slash */,
+ 0x009b /* zero */,
+ 0x00a6 /* one */,
+ 0x00b1 /* two */,
+ 0x00bc /* three */,
+ 0x00c7 /* four */,
+ 0x00d2 /* five */,
+ 0x00dd /* six */,
+ 0x00e8 /* seven */,
+ 0x00f3 /* eight */,
+ 0x00fe /* nine */,
+ 0x0109 /* colon */,
+ 0x0113 /* semicolon */,
+ 0x011e /* less */,
+ 0x0128 /* equal */,
+ 0x0130 /* greater */,
+ 0x013a /* question */,
+ 0x0146 /* at */,
+ 0x0152 /* A */,
+ 0x015d /* B */,
+ 0x0168 /* C */,
+ 0x0173 /* D */,
+ 0x017e /* E */,
+ 0x0189 /* F */,
+ 0x0194 /* G */,
+ 0x019f /* H */,
+ 0x01aa /* I */,
+ 0x01b5 /* J */,
+ 0x01c0 /* K */,
+ 0x01cb /* L */,
+ 0x01d6 /* M */,
+ 0x01e1 /* N */,
+ 0x01ec /* O */,
+ 0x01f7 /* P */,
+ 0x0202 /* Q */,
+ 0x020e /* R */,
+ 0x0219 /* S */,
+ 0x0224 /* T */,
+ 0x022f /* U */,
+ 0x023a /* V */,
+ 0x0245 /* W */,
+ 0x0250 /* X */,
+ 0x025b /* Y */,
+ 0x0266 /* Z */,
+ 0x0271 /* bracketleft */,
+ 0x027e /* backslash */,
+ 0x0289 /* bracketright */,
+ 0x0296 /* asciicircum */,
+ 0x029e /* underscore */,
+ 0x02a4 /* grave */,
+ 0x02ab /* a */,
+ 0x02b5 /* b */,
+ 0x02c1 /* c */,
+ 0x02cb /* d */,
+ 0x02d7 /* e */,
+ 0x02e1 /* f */,
+ 0x02ed /* g */,
+ 0x02f8 /* h */,
+ 0x0304 /* i */,
+ 0x0310 /* j */,
+ 0x031d /* k */,
+ 0x0329 /* l */,
+ 0x0335 /* m */,
+ 0x033f /* n */,
+ 0x0349 /* o */,
+ 0x0353 /* p */,
+ 0x035e /* q */,
+ 0x0369 /* r */,
+ 0x0373 /* s */,
+ 0x037d /* t */,
+ 0x0389 /* u */,
+ 0x0393 /* v */,
+ 0x039d /* w */,
+ 0x03a7 /* x */,
+ 0x03b1 /* y */,
+ 0x03bc /* z */,
+ 0x03c6 /* braceleft */,
+ 0x03d2 /* bar */,
+ 0x03de /* braceright */,
+ 0x03ea /* asciitilde */,
+ 0xffff /* (no glyph) */
+};
+const struct fb_font font_helvB08 = {
+ .height = 10,
+ .ascent = 8,
+ .firstchar = 32, /* space */
+ .lastchar = 127, /* ? */
+ .chardata = font_helvB08_data,
+ .charoffs = font_helvB08_offsets,
+};
diff --git a/src/target/firmware/fb/helvB14.c b/src/target/firmware/fb/helvB14.c
new file mode 100644
index 00000000..40c310ee
--- /dev/null
+++ b/src/target/firmware/fb/helvB14.c
@@ -0,0 +1,1195 @@
+#include <fb/font.h>
+static const uint8_t font_helvB14_data[] = {
+/* --- new character space (32) starting at offset 0x0000 --- */
+ /*0000:*/ 4, 1, 1, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x00, /* ........ */
+/* --- new character exclam (33) starting at offset 0x0006 --- */
+ /*0006:*/ 4, 2, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*000b:*/ 0xc0, /* ##...... */
+ /*000c:*/ 0xc0, /* ##...... */
+ /*000d:*/ 0xc0, /* ##...... */
+ /*000e:*/ 0xc0, /* ##...... */
+ /*000f:*/ 0xc0, /* ##...... */
+ /*0010:*/ 0xc0, /* ##...... */
+ /*0011:*/ 0x80, /* #....... */
+ /*0012:*/ 0x80, /* #....... */
+ /*0013:*/ 0x00, /* ........ */
+ /*0014:*/ 0xc0, /* ##...... */
+ /*0015:*/ 0xc0, /* ##...... */
+/* --- new character quotedbl (34) starting at offset 0x0016 --- */
+ /*0016:*/ 7, 5, 3, 1, 8, /* width and bbox (w,h,x,y) */
+ /*001b:*/ 0xd8, /* ##.##... */
+ /*001c:*/ 0xd8, /* ##.##... */
+ /*001d:*/ 0x90, /* #..#.... */
+/* --- new character numbersign (35) starting at offset 0x001e --- */
+ /*001e:*/ 9, 9, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0023:*/ 0x1b,0x00, /* ...##.##........ */
+ /*0025:*/ 0x1b,0x00, /* ...##.##........ */
+ /*0027:*/ 0x1b,0x00, /* ...##.##........ */
+ /*0029:*/ 0x7f,0x80, /* .########....... */
+ /*002b:*/ 0x36,0x00, /* ..##.##......... */
+ /*002d:*/ 0x36,0x00, /* ..##.##......... */
+ /*002f:*/ 0xff,0x00, /* ########........ */
+ /*0031:*/ 0x6c,0x00, /* .##.##.......... */
+ /*0033:*/ 0x6c,0x00, /* .##.##.......... */
+ /*0035:*/ 0x6c,0x00, /* .##.##.......... */
+/* --- new character dollar (36) starting at offset 0x0037 --- */
+ /*0037:*/ 8, 7, 13, 0, -2, /* width and bbox (w,h,x,y) */
+ /*003c:*/ 0x10, /* ...#.... */
+ /*003d:*/ 0x7c, /* .#####.. */
+ /*003e:*/ 0xd6, /* ##.#.##. */
+ /*003f:*/ 0xd6, /* ##.#.##. */
+ /*0040:*/ 0xf0, /* ####.... */
+ /*0041:*/ 0x78, /* .####... */
+ /*0042:*/ 0x1c, /* ...###.. */
+ /*0043:*/ 0x16, /* ...#.##. */
+ /*0044:*/ 0xd6, /* ##.#.##. */
+ /*0045:*/ 0xd6, /* ##.#.##. */
+ /*0046:*/ 0x7c, /* .#####.. */
+ /*0047:*/ 0x10, /* ...#.... */
+ /*0048:*/ 0x10, /* ...#.... */
+/* --- new character percent (37) starting at offset 0x0049 --- */
+ /*0049:*/ 13, 12, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*004e:*/ 0x78,0x80, /* .####...#....... */
+ /*0050:*/ 0xcd,0x80, /* ##..##.##....... */
+ /*0052:*/ 0xcd,0x00, /* ##..##.#........ */
+ /*0054:*/ 0x7b,0x00, /* .####.##........ */
+ /*0056:*/ 0x06,0x00, /* .....##......... */
+ /*0058:*/ 0x04,0x00, /* .....#.......... */
+ /*005a:*/ 0x0d,0xe0, /* ....##.####..... */
+ /*005c:*/ 0x0b,0x30, /* ....#.##..##.... */
+ /*005e:*/ 0x1b,0x30, /* ...##.##..##.... */
+ /*0060:*/ 0x11,0xe0, /* ...#...####..... */
+/* --- new character ampersand (38) starting at offset 0x0062 --- */
+ /*0062:*/ 11, 9, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0067:*/ 0x38,0x00, /* ..###........... */
+ /*0069:*/ 0x6c,0x00, /* .##.##.......... */
+ /*006b:*/ 0x6c,0x00, /* .##.##.......... */
+ /*006d:*/ 0x38,0x00, /* ..###........... */
+ /*006f:*/ 0x73,0x00, /* .###..##........ */
+ /*0071:*/ 0xfb,0x00, /* #####.##........ */
+ /*0073:*/ 0xce,0x00, /* ##..###......... */
+ /*0075:*/ 0xc6,0x00, /* ##...##......... */
+ /*0077:*/ 0xcf,0x00, /* ##..####........ */
+ /*0079:*/ 0x7d,0x80, /* .#####.##....... */
+/* --- new character quotesingle (39) starting at offset 0x007b --- */
+ /*007b:*/ 4, 2, 3, 1, 8, /* width and bbox (w,h,x,y) */
+ /*0080:*/ 0xc0, /* ##...... */
+ /*0081:*/ 0xc0, /* ##...... */
+ /*0082:*/ 0x80, /* #....... */
+/* --- new character parenleft (40) starting at offset 0x0083 --- */
+ /*0083:*/ 5, 4, 14, 0, -3, /* width and bbox (w,h,x,y) */
+ /*0088:*/ 0x30, /* ..##.... */
+ /*0089:*/ 0x60, /* .##..... */
+ /*008a:*/ 0x60, /* .##..... */
+ /*008b:*/ 0xc0, /* ##...... */
+ /*008c:*/ 0xc0, /* ##...... */
+ /*008d:*/ 0xc0, /* ##...... */
+ /*008e:*/ 0xc0, /* ##...... */
+ /*008f:*/ 0xc0, /* ##...... */
+ /*0090:*/ 0xc0, /* ##...... */
+ /*0091:*/ 0xc0, /* ##...... */
+ /*0092:*/ 0xc0, /* ##...... */
+ /*0093:*/ 0x60, /* .##..... */
+ /*0094:*/ 0x60, /* .##..... */
+ /*0095:*/ 0x30, /* ..##.... */
+/* --- new character parenright (41) starting at offset 0x0096 --- */
+ /*0096:*/ 5, 4, 14, 1, -3, /* width and bbox (w,h,x,y) */
+ /*009b:*/ 0xc0, /* ##...... */
+ /*009c:*/ 0x60, /* .##..... */
+ /*009d:*/ 0x60, /* .##..... */
+ /*009e:*/ 0x30, /* ..##.... */
+ /*009f:*/ 0x30, /* ..##.... */
+ /*00a0:*/ 0x30, /* ..##.... */
+ /*00a1:*/ 0x30, /* ..##.... */
+ /*00a2:*/ 0x30, /* ..##.... */
+ /*00a3:*/ 0x30, /* ..##.... */
+ /*00a4:*/ 0x30, /* ..##.... */
+ /*00a5:*/ 0x30, /* ..##.... */
+ /*00a6:*/ 0x60, /* .##..... */
+ /*00a7:*/ 0x60, /* .##..... */
+ /*00a8:*/ 0xc0, /* ##...... */
+/* --- new character asterisk (42) starting at offset 0x00a9 --- */
+ /*00a9:*/ 6, 5, 4, 0, 7, /* width and bbox (w,h,x,y) */
+ /*00ae:*/ 0x20, /* ..#..... */
+ /*00af:*/ 0xf8, /* #####... */
+ /*00b0:*/ 0x70, /* .###.... */
+ /*00b1:*/ 0xd8, /* ##.##... */
+/* --- new character plus (43) starting at offset 0x00b2 --- */
+ /*00b2:*/ 9, 8, 7, 0, 1, /* width and bbox (w,h,x,y) */
+ /*00b7:*/ 0x18, /* ...##... */
+ /*00b8:*/ 0x18, /* ...##... */
+ /*00b9:*/ 0x18, /* ...##... */
+ /*00ba:*/ 0xff, /* ######## */
+ /*00bb:*/ 0x18, /* ...##... */
+ /*00bc:*/ 0x18, /* ...##... */
+ /*00bd:*/ 0x18, /* ...##... */
+/* --- new character comma (44) starting at offset 0x00be --- */
+ /*00be:*/ 4, 3, 3, 0, -1, /* width and bbox (w,h,x,y) */
+ /*00c3:*/ 0x60, /* .##..... */
+ /*00c4:*/ 0x60, /* .##..... */
+ /*00c5:*/ 0xc0, /* ##...... */
+/* --- new character hyphen (45) starting at offset 0x00c6 --- */
+ /*00c6:*/ 5, 5, 1, 0, 4, /* width and bbox (w,h,x,y) */
+ /*00cb:*/ 0xf8, /* #####... */
+/* --- new character period (46) starting at offset 0x00cc --- */
+ /*00cc:*/ 4, 2, 2, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00d1:*/ 0xc0, /* ##...... */
+ /*00d2:*/ 0xc0, /* ##...... */
+/* --- new character slash (47) starting at offset 0x00d3 --- */
+ /*00d3:*/ 4, 4, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00d8:*/ 0x30, /* ..##.... */
+ /*00d9:*/ 0x30, /* ..##.... */
+ /*00da:*/ 0x20, /* ..#..... */
+ /*00db:*/ 0x20, /* ..#..... */
+ /*00dc:*/ 0x60, /* .##..... */
+ /*00dd:*/ 0x60, /* .##..... */
+ /*00de:*/ 0x60, /* .##..... */
+ /*00df:*/ 0x40, /* .#...... */
+ /*00e0:*/ 0x40, /* .#...... */
+ /*00e1:*/ 0xc0, /* ##...... */
+ /*00e2:*/ 0xc0, /* ##...... */
+/* --- new character zero (48) starting at offset 0x00e3 --- */
+ /*00e3:*/ 8, 7, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00e8:*/ 0x38, /* ..###... */
+ /*00e9:*/ 0x6c, /* .##.##.. */
+ /*00ea:*/ 0xc6, /* ##...##. */
+ /*00eb:*/ 0xc6, /* ##...##. */
+ /*00ec:*/ 0xc6, /* ##...##. */
+ /*00ed:*/ 0xc6, /* ##...##. */
+ /*00ee:*/ 0xc6, /* ##...##. */
+ /*00ef:*/ 0xc6, /* ##...##. */
+ /*00f0:*/ 0x6c, /* .##.##.. */
+ /*00f1:*/ 0x38, /* ..###... */
+/* --- new character one (49) starting at offset 0x00f2 --- */
+ /*00f2:*/ 8, 4, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00f7:*/ 0x30, /* ..##.... */
+ /*00f8:*/ 0xf0, /* ####.... */
+ /*00f9:*/ 0x30, /* ..##.... */
+ /*00fa:*/ 0x30, /* ..##.... */
+ /*00fb:*/ 0x30, /* ..##.... */
+ /*00fc:*/ 0x30, /* ..##.... */
+ /*00fd:*/ 0x30, /* ..##.... */
+ /*00fe:*/ 0x30, /* ..##.... */
+ /*00ff:*/ 0x30, /* ..##.... */
+ /*0100:*/ 0x30, /* ..##.... */
+/* --- new character two (50) starting at offset 0x0101 --- */
+ /*0101:*/ 8, 7, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0106:*/ 0x7c, /* .#####.. */
+ /*0107:*/ 0xe6, /* ###..##. */
+ /*0108:*/ 0xc6, /* ##...##. */
+ /*0109:*/ 0x0e, /* ....###. */
+ /*010a:*/ 0x0c, /* ....##.. */
+ /*010b:*/ 0x38, /* ..###... */
+ /*010c:*/ 0x70, /* .###.... */
+ /*010d:*/ 0xe0, /* ###..... */
+ /*010e:*/ 0xc0, /* ##...... */
+ /*010f:*/ 0xfe, /* #######. */
+/* --- new character three (51) starting at offset 0x0110 --- */
+ /*0110:*/ 8, 7, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0115:*/ 0x7c, /* .#####.. */
+ /*0116:*/ 0xce, /* ##..###. */
+ /*0117:*/ 0xc6, /* ##...##. */
+ /*0118:*/ 0x06, /* .....##. */
+ /*0119:*/ 0x3c, /* ..####.. */
+ /*011a:*/ 0x06, /* .....##. */
+ /*011b:*/ 0x06, /* .....##. */
+ /*011c:*/ 0xc6, /* ##...##. */
+ /*011d:*/ 0xce, /* ##..###. */
+ /*011e:*/ 0x7c, /* .#####.. */
+/* --- new character four (52) starting at offset 0x011f --- */
+ /*011f:*/ 8, 8, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0124:*/ 0x0e, /* ....###. */
+ /*0125:*/ 0x1e, /* ...####. */
+ /*0126:*/ 0x36, /* ..##.##. */
+ /*0127:*/ 0x66, /* .##..##. */
+ /*0128:*/ 0xc6, /* ##...##. */
+ /*0129:*/ 0xc6, /* ##...##. */
+ /*012a:*/ 0xff, /* ######## */
+ /*012b:*/ 0x06, /* .....##. */
+ /*012c:*/ 0x06, /* .....##. */
+ /*012d:*/ 0x06, /* .....##. */
+/* --- new character five (53) starting at offset 0x012e --- */
+ /*012e:*/ 8, 7, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0133:*/ 0x7e, /* .######. */
+ /*0134:*/ 0x60, /* .##..... */
+ /*0135:*/ 0xc0, /* ##...... */
+ /*0136:*/ 0xf8, /* #####... */
+ /*0137:*/ 0x1c, /* ...###.. */
+ /*0138:*/ 0x06, /* .....##. */
+ /*0139:*/ 0x06, /* .....##. */
+ /*013a:*/ 0xc6, /* ##...##. */
+ /*013b:*/ 0xec, /* ###.##.. */
+ /*013c:*/ 0x78, /* .####... */
+/* --- new character six (54) starting at offset 0x013d --- */
+ /*013d:*/ 8, 7, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0142:*/ 0x3c, /* ..####.. */
+ /*0143:*/ 0x76, /* .###.##. */
+ /*0144:*/ 0x66, /* .##..##. */
+ /*0145:*/ 0xc0, /* ##...... */
+ /*0146:*/ 0xdc, /* ##.###.. */
+ /*0147:*/ 0xf6, /* ####.##. */
+ /*0148:*/ 0xc6, /* ##...##. */
+ /*0149:*/ 0xc6, /* ##...##. */
+ /*014a:*/ 0x6e, /* .##.###. */
+ /*014b:*/ 0x3c, /* ..####.. */
+/* --- new character seven (55) starting at offset 0x014c --- */
+ /*014c:*/ 8, 7, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0151:*/ 0xfe, /* #######. */
+ /*0152:*/ 0x06, /* .....##. */
+ /*0153:*/ 0x0c, /* ....##.. */
+ /*0154:*/ 0x0c, /* ....##.. */
+ /*0155:*/ 0x18, /* ...##... */
+ /*0156:*/ 0x18, /* ...##... */
+ /*0157:*/ 0x30, /* ..##.... */
+ /*0158:*/ 0x30, /* ..##.... */
+ /*0159:*/ 0x60, /* .##..... */
+ /*015a:*/ 0x60, /* .##..... */
+/* --- new character eight (56) starting at offset 0x015b --- */
+ /*015b:*/ 8, 7, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0160:*/ 0x7c, /* .#####.. */
+ /*0161:*/ 0xee, /* ###.###. */
+ /*0162:*/ 0xc6, /* ##...##. */
+ /*0163:*/ 0xc6, /* ##...##. */
+ /*0164:*/ 0x7c, /* .#####.. */
+ /*0165:*/ 0xee, /* ###.###. */
+ /*0166:*/ 0xc6, /* ##...##. */
+ /*0167:*/ 0xc6, /* ##...##. */
+ /*0168:*/ 0xc6, /* ##...##. */
+ /*0169:*/ 0x7c, /* .#####.. */
+/* --- new character nine (57) starting at offset 0x016a --- */
+ /*016a:*/ 8, 7, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*016f:*/ 0x7c, /* .#####.. */
+ /*0170:*/ 0xee, /* ###.###. */
+ /*0171:*/ 0xc6, /* ##...##. */
+ /*0172:*/ 0xc6, /* ##...##. */
+ /*0173:*/ 0xe6, /* ###..##. */
+ /*0174:*/ 0x7e, /* .######. */
+ /*0175:*/ 0x06, /* .....##. */
+ /*0176:*/ 0xc6, /* ##...##. */
+ /*0177:*/ 0xce, /* ##..###. */
+ /*0178:*/ 0x7c, /* .#####.. */
+/* --- new character colon (58) starting at offset 0x0179 --- */
+ /*0179:*/ 5, 2, 8, 2, 0, /* width and bbox (w,h,x,y) */
+ /*017e:*/ 0xc0, /* ##...... */
+ /*017f:*/ 0xc0, /* ##...... */
+ /*0180:*/ 0x00, /* ........ */
+ /*0181:*/ 0x00, /* ........ */
+ /*0182:*/ 0x00, /* ........ */
+ /*0183:*/ 0x00, /* ........ */
+ /*0184:*/ 0xc0, /* ##...... */
+ /*0185:*/ 0xc0, /* ##...... */
+/* --- new character semicolon (59) starting at offset 0x0186 --- */
+ /*0186:*/ 5, 3, 9, 1, -1, /* width and bbox (w,h,x,y) */
+ /*018b:*/ 0x60, /* .##..... */
+ /*018c:*/ 0x60, /* .##..... */
+ /*018d:*/ 0x00, /* ........ */
+ /*018e:*/ 0x00, /* ........ */
+ /*018f:*/ 0x00, /* ........ */
+ /*0190:*/ 0x00, /* ........ */
+ /*0191:*/ 0x60, /* .##..... */
+ /*0192:*/ 0x60, /* .##..... */
+ /*0193:*/ 0xc0, /* ##...... */
+/* --- new character less (60) starting at offset 0x0194 --- */
+ /*0194:*/ 8, 6, 5, 1, 2, /* width and bbox (w,h,x,y) */
+ /*0199:*/ 0x1c, /* ...###.. */
+ /*019a:*/ 0x70, /* .###.... */
+ /*019b:*/ 0xc0, /* ##...... */
+ /*019c:*/ 0x70, /* .###.... */
+ /*019d:*/ 0x1c, /* ...###.. */
+/* --- new character equal (61) starting at offset 0x019e --- */
+ /*019e:*/ 9, 7, 3, 1, 3, /* width and bbox (w,h,x,y) */
+ /*01a3:*/ 0xfe, /* #######. */
+ /*01a4:*/ 0x00, /* ........ */
+ /*01a5:*/ 0xfe, /* #######. */
+/* --- new character greater (62) starting at offset 0x01a6 --- */
+ /*01a6:*/ 8, 6, 5, 1, 2, /* width and bbox (w,h,x,y) */
+ /*01ab:*/ 0xe0, /* ###..... */
+ /*01ac:*/ 0x38, /* ..###... */
+ /*01ad:*/ 0x0c, /* ....##.. */
+ /*01ae:*/ 0x38, /* ..###... */
+ /*01af:*/ 0xe0, /* ###..... */
+/* --- new character question (63) starting at offset 0x01b0 --- */
+ /*01b0:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01b5:*/ 0x7c, /* .#####.. */
+ /*01b6:*/ 0xc6, /* ##...##. */
+ /*01b7:*/ 0xc6, /* ##...##. */
+ /*01b8:*/ 0x06, /* .....##. */
+ /*01b9:*/ 0x0c, /* ....##.. */
+ /*01ba:*/ 0x18, /* ...##... */
+ /*01bb:*/ 0x30, /* ..##.... */
+ /*01bc:*/ 0x30, /* ..##.... */
+ /*01bd:*/ 0x00, /* ........ */
+ /*01be:*/ 0x30, /* ..##.... */
+ /*01bf:*/ 0x30, /* ..##.... */
+/* --- new character at (64) starting at offset 0x01c0 --- */
+ /*01c0:*/ 14, 13, 12, 0, -1, /* width and bbox (w,h,x,y) */
+ /*01c5:*/ 0x0f,0x80, /* ....#####....... */
+ /*01c7:*/ 0x38,0xe0, /* ..###...###..... */
+ /*01c9:*/ 0x70,0x70, /* .###.....###.... */
+ /*01cb:*/ 0x66,0xb0, /* .##..##.#.##.... */
+ /*01cd:*/ 0xcd,0x98, /* ##..##.##..##... */
+ /*01cf:*/ 0xd9,0x98, /* ##.##..##..##... */
+ /*01d1:*/ 0xdb,0x18, /* ##.##.##...##... */
+ /*01d3:*/ 0xdb,0x30, /* ##.##.##..##.... */
+ /*01d5:*/ 0xce,0xe0, /* ##..###.###..... */
+ /*01d7:*/ 0x60,0x00, /* .##............. */
+ /*01d9:*/ 0x31,0x80, /* ..##...##....... */
+ /*01db:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character A (65) starting at offset 0x01dd --- */
+ /*01dd:*/ 10, 10, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01e2:*/ 0x0c,0x00, /* ....##.......... */
+ /*01e4:*/ 0x0c,0x00, /* ....##.......... */
+ /*01e6:*/ 0x1e,0x00, /* ...####......... */
+ /*01e8:*/ 0x12,0x00, /* ...#..#......... */
+ /*01ea:*/ 0x33,0x00, /* ..##..##........ */
+ /*01ec:*/ 0x33,0x00, /* ..##..##........ */
+ /*01ee:*/ 0x61,0x80, /* .##....##....... */
+ /*01f0:*/ 0x7f,0x80, /* .########....... */
+ /*01f2:*/ 0x61,0x80, /* .##....##....... */
+ /*01f4:*/ 0xc0,0xc0, /* ##......##...... */
+ /*01f6:*/ 0xc0,0xc0, /* ##......##...... */
+/* --- new character B (66) starting at offset 0x01f8 --- */
+ /*01f8:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01fd:*/ 0xfe, /* #######. */
+ /*01fe:*/ 0xc7, /* ##...### */
+ /*01ff:*/ 0xc3, /* ##....## */
+ /*0200:*/ 0xc3, /* ##....## */
+ /*0201:*/ 0xc6, /* ##...##. */
+ /*0202:*/ 0xfc, /* ######.. */
+ /*0203:*/ 0xc6, /* ##...##. */
+ /*0204:*/ 0xc3, /* ##....## */
+ /*0205:*/ 0xc3, /* ##....## */
+ /*0206:*/ 0xc7, /* ##...### */
+ /*0207:*/ 0xfe, /* #######. */
+/* --- new character C (67) starting at offset 0x0208 --- */
+ /*0208:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*020d:*/ 0x1f,0x00, /* ...#####........ */
+ /*020f:*/ 0x7b,0x80, /* .####.###....... */
+ /*0211:*/ 0x60,0x80, /* .##.....#....... */
+ /*0213:*/ 0xc0,0x00, /* ##.............. */
+ /*0215:*/ 0xc0,0x00, /* ##.............. */
+ /*0217:*/ 0xc0,0x00, /* ##.............. */
+ /*0219:*/ 0xc0,0x00, /* ##.............. */
+ /*021b:*/ 0xc0,0x00, /* ##.............. */
+ /*021d:*/ 0x60,0x80, /* .##.....#....... */
+ /*021f:*/ 0x7b,0x80, /* .####.###....... */
+ /*0221:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character D (68) starting at offset 0x0223 --- */
+ /*0223:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0228:*/ 0xfc,0x00, /* ######.......... */
+ /*022a:*/ 0xc7,0x00, /* ##...###........ */
+ /*022c:*/ 0xc3,0x00, /* ##....##........ */
+ /*022e:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0230:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0232:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0234:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0236:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0238:*/ 0xc3,0x00, /* ##....##........ */
+ /*023a:*/ 0xc7,0x00, /* ##...###........ */
+ /*023c:*/ 0xfc,0x00, /* ######.......... */
+/* --- new character E (69) starting at offset 0x023e --- */
+ /*023e:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0243:*/ 0xfe, /* #######. */
+ /*0244:*/ 0xc0, /* ##...... */
+ /*0245:*/ 0xc0, /* ##...... */
+ /*0246:*/ 0xc0, /* ##...... */
+ /*0247:*/ 0xc0, /* ##...... */
+ /*0248:*/ 0xfe, /* #######. */
+ /*0249:*/ 0xc0, /* ##...... */
+ /*024a:*/ 0xc0, /* ##...... */
+ /*024b:*/ 0xc0, /* ##...... */
+ /*024c:*/ 0xc0, /* ##...... */
+ /*024d:*/ 0xfe, /* #######. */
+/* --- new character F (70) starting at offset 0x024e --- */
+ /*024e:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0253:*/ 0xfe, /* #######. */
+ /*0254:*/ 0xc0, /* ##...... */
+ /*0255:*/ 0xc0, /* ##...... */
+ /*0256:*/ 0xc0, /* ##...... */
+ /*0257:*/ 0xc0, /* ##...... */
+ /*0258:*/ 0xfc, /* ######.. */
+ /*0259:*/ 0xc0, /* ##...... */
+ /*025a:*/ 0xc0, /* ##...... */
+ /*025b:*/ 0xc0, /* ##...... */
+ /*025c:*/ 0xc0, /* ##...... */
+ /*025d:*/ 0xc0, /* ##...... */
+/* --- new character G (71) starting at offset 0x025e --- */
+ /*025e:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0263:*/ 0x1f,0x00, /* ...#####........ */
+ /*0265:*/ 0x7b,0x80, /* .####.###....... */
+ /*0267:*/ 0x60,0x80, /* .##.....#....... */
+ /*0269:*/ 0xc0,0x00, /* ##.............. */
+ /*026b:*/ 0xc0,0x00, /* ##.............. */
+ /*026d:*/ 0xc7,0x80, /* ##...####....... */
+ /*026f:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0271:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0273:*/ 0x61,0x80, /* .##....##....... */
+ /*0275:*/ 0x7b,0x80, /* .####.###....... */
+ /*0277:*/ 0x1e,0x80, /* ...####.#....... */
+/* --- new character H (72) starting at offset 0x0279 --- */
+ /*0279:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*027e:*/ 0xc3, /* ##....## */
+ /*027f:*/ 0xc3, /* ##....## */
+ /*0280:*/ 0xc3, /* ##....## */
+ /*0281:*/ 0xc3, /* ##....## */
+ /*0282:*/ 0xc3, /* ##....## */
+ /*0283:*/ 0xff, /* ######## */
+ /*0284:*/ 0xc3, /* ##....## */
+ /*0285:*/ 0xc3, /* ##....## */
+ /*0286:*/ 0xc3, /* ##....## */
+ /*0287:*/ 0xc3, /* ##....## */
+ /*0288:*/ 0xc3, /* ##....## */
+/* --- new character I (73) starting at offset 0x0289 --- */
+ /*0289:*/ 4, 2, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*028e:*/ 0xc0, /* ##...... */
+ /*028f:*/ 0xc0, /* ##...... */
+ /*0290:*/ 0xc0, /* ##...... */
+ /*0291:*/ 0xc0, /* ##...... */
+ /*0292:*/ 0xc0, /* ##...... */
+ /*0293:*/ 0xc0, /* ##...... */
+ /*0294:*/ 0xc0, /* ##...... */
+ /*0295:*/ 0xc0, /* ##...... */
+ /*0296:*/ 0xc0, /* ##...... */
+ /*0297:*/ 0xc0, /* ##...... */
+ /*0298:*/ 0xc0, /* ##...... */
+/* --- new character J (74) starting at offset 0x0299 --- */
+ /*0299:*/ 8, 7, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*029e:*/ 0x06, /* .....##. */
+ /*029f:*/ 0x06, /* .....##. */
+ /*02a0:*/ 0x06, /* .....##. */
+ /*02a1:*/ 0x06, /* .....##. */
+ /*02a2:*/ 0x06, /* .....##. */
+ /*02a3:*/ 0x06, /* .....##. */
+ /*02a4:*/ 0x06, /* .....##. */
+ /*02a5:*/ 0xc6, /* ##...##. */
+ /*02a6:*/ 0xc6, /* ##...##. */
+ /*02a7:*/ 0xee, /* ###.###. */
+ /*02a8:*/ 0x7c, /* .#####.. */
+/* --- new character K (75) starting at offset 0x02a9 --- */
+ /*02a9:*/ 10, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02ae:*/ 0xc3,0x00, /* ##....##........ */
+ /*02b0:*/ 0xc6,0x00, /* ##...##......... */
+ /*02b2:*/ 0xcc,0x00, /* ##..##.......... */
+ /*02b4:*/ 0xd8,0x00, /* ##.##........... */
+ /*02b6:*/ 0xf0,0x00, /* ####............ */
+ /*02b8:*/ 0xf0,0x00, /* ####............ */
+ /*02ba:*/ 0xd8,0x00, /* ##.##........... */
+ /*02bc:*/ 0xcc,0x00, /* ##..##.......... */
+ /*02be:*/ 0xc6,0x00, /* ##...##......... */
+ /*02c0:*/ 0xc3,0x00, /* ##....##........ */
+ /*02c2:*/ 0xc1,0x80, /* ##.....##....... */
+/* --- new character L (76) starting at offset 0x02c4 --- */
+ /*02c4:*/ 8, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02c9:*/ 0xc0, /* ##...... */
+ /*02ca:*/ 0xc0, /* ##...... */
+ /*02cb:*/ 0xc0, /* ##...... */
+ /*02cc:*/ 0xc0, /* ##...... */
+ /*02cd:*/ 0xc0, /* ##...... */
+ /*02ce:*/ 0xc0, /* ##...... */
+ /*02cf:*/ 0xc0, /* ##...... */
+ /*02d0:*/ 0xc0, /* ##...... */
+ /*02d1:*/ 0xc0, /* ##...... */
+ /*02d2:*/ 0xc0, /* ##...... */
+ /*02d3:*/ 0xfe, /* #######. */
+/* --- new character M (77) starting at offset 0x02d4 --- */
+ /*02d4:*/ 13, 11, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02d9:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02db:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02dd:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*02df:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*02e1:*/ 0xf1,0xe0, /* ####...####..... */
+ /*02e3:*/ 0xd1,0x60, /* ##.#...#.##..... */
+ /*02e5:*/ 0xd1,0x60, /* ##.#...#.##..... */
+ /*02e7:*/ 0xdb,0x60, /* ##.##.##.##..... */
+ /*02e9:*/ 0xca,0x60, /* ##..#.#..##..... */
+ /*02eb:*/ 0xce,0x60, /* ##..###..##..... */
+ /*02ed:*/ 0xc4,0x60, /* ##...#...##..... */
+/* --- new character N (78) starting at offset 0x02ef --- */
+ /*02ef:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02f4:*/ 0xc1,0x80, /* ##.....##....... */
+ /*02f6:*/ 0xe1,0x80, /* ###....##....... */
+ /*02f8:*/ 0xe1,0x80, /* ###....##....... */
+ /*02fa:*/ 0xd1,0x80, /* ##.#...##....... */
+ /*02fc:*/ 0xd9,0x80, /* ##.##..##....... */
+ /*02fe:*/ 0xc9,0x80, /* ##..#..##....... */
+ /*0300:*/ 0xcd,0x80, /* ##..##.##....... */
+ /*0302:*/ 0xc5,0x80, /* ##...#.##....... */
+ /*0304:*/ 0xc3,0x80, /* ##....###....... */
+ /*0306:*/ 0xc3,0x80, /* ##....###....... */
+ /*0308:*/ 0xc1,0x80, /* ##.....##....... */
+/* --- new character O (79) starting at offset 0x030a --- */
+ /*030a:*/ 12, 10, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*030f:*/ 0x1e,0x00, /* ...####......... */
+ /*0311:*/ 0x73,0x80, /* .###..###....... */
+ /*0313:*/ 0x61,0x80, /* .##....##....... */
+ /*0315:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0317:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0319:*/ 0xc0,0xc0, /* ##......##...... */
+ /*031b:*/ 0xc0,0xc0, /* ##......##...... */
+ /*031d:*/ 0xc0,0xc0, /* ##......##...... */
+ /*031f:*/ 0x61,0x80, /* .##....##....... */
+ /*0321:*/ 0x73,0x80, /* .###..###....... */
+ /*0323:*/ 0x1e,0x00, /* ...####......... */
+/* --- new character P (80) starting at offset 0x0325 --- */
+ /*0325:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*032a:*/ 0xfe, /* #######. */
+ /*032b:*/ 0xc7, /* ##...### */
+ /*032c:*/ 0xc3, /* ##....## */
+ /*032d:*/ 0xc3, /* ##....## */
+ /*032e:*/ 0xc7, /* ##...### */
+ /*032f:*/ 0xfe, /* #######. */
+ /*0330:*/ 0xc0, /* ##...... */
+ /*0331:*/ 0xc0, /* ##...... */
+ /*0332:*/ 0xc0, /* ##...... */
+ /*0333:*/ 0xc0, /* ##...... */
+ /*0334:*/ 0xc0, /* ##...... */
+/* --- new character Q (81) starting at offset 0x0335 --- */
+ /*0335:*/ 12, 10, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*033a:*/ 0x1e,0x00, /* ...####......... */
+ /*033c:*/ 0x73,0x80, /* .###..###....... */
+ /*033e:*/ 0x61,0x80, /* .##....##....... */
+ /*0340:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0342:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0344:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0346:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0348:*/ 0xc6,0xc0, /* ##...##.##...... */
+ /*034a:*/ 0x63,0x80, /* .##...###....... */
+ /*034c:*/ 0x73,0x80, /* .###..###....... */
+ /*034e:*/ 0x1e,0xc0, /* ...####.##...... */
+/* --- new character R (82) starting at offset 0x0350 --- */
+ /*0350:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0355:*/ 0xfe,0x00, /* #######......... */
+ /*0357:*/ 0xc7,0x00, /* ##...###........ */
+ /*0359:*/ 0xc3,0x00, /* ##....##........ */
+ /*035b:*/ 0xc3,0x00, /* ##....##........ */
+ /*035d:*/ 0xc7,0x00, /* ##...###........ */
+ /*035f:*/ 0xfe,0x00, /* #######......... */
+ /*0361:*/ 0xc3,0x00, /* ##....##........ */
+ /*0363:*/ 0xc3,0x00, /* ##....##........ */
+ /*0365:*/ 0xc3,0x00, /* ##....##........ */
+ /*0367:*/ 0xc3,0x00, /* ##....##........ */
+ /*0369:*/ 0xc1,0x80, /* ##.....##....... */
+/* --- new character S (83) starting at offset 0x036b --- */
+ /*036b:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0370:*/ 0x7e, /* .######. */
+ /*0371:*/ 0xe7, /* ###..### */
+ /*0372:*/ 0xc3, /* ##....## */
+ /*0373:*/ 0xe0, /* ###..... */
+ /*0374:*/ 0x78, /* .####... */
+ /*0375:*/ 0x1e, /* ...####. */
+ /*0376:*/ 0x07, /* .....### */
+ /*0377:*/ 0x03, /* ......## */
+ /*0378:*/ 0xc3, /* ##....## */
+ /*0379:*/ 0xee, /* ###.###. */
+ /*037a:*/ 0x7c, /* .#####.. */
+/* --- new character T (84) starting at offset 0x037b --- */
+ /*037b:*/ 8, 8, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0380:*/ 0xff, /* ######## */
+ /*0381:*/ 0x18, /* ...##... */
+ /*0382:*/ 0x18, /* ...##... */
+ /*0383:*/ 0x18, /* ...##... */
+ /*0384:*/ 0x18, /* ...##... */
+ /*0385:*/ 0x18, /* ...##... */
+ /*0386:*/ 0x18, /* ...##... */
+ /*0387:*/ 0x18, /* ...##... */
+ /*0388:*/ 0x18, /* ...##... */
+ /*0389:*/ 0x18, /* ...##... */
+ /*038a:*/ 0x18, /* ...##... */
+/* --- new character U (85) starting at offset 0x038b --- */
+ /*038b:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0390:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0392:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0394:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0396:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0398:*/ 0xc1,0x80, /* ##.....##....... */
+ /*039a:*/ 0xc1,0x80, /* ##.....##....... */
+ /*039c:*/ 0xc1,0x80, /* ##.....##....... */
+ /*039e:*/ 0xc1,0x80, /* ##.....##....... */
+ /*03a0:*/ 0xc1,0x80, /* ##.....##....... */
+ /*03a2:*/ 0x63,0x00, /* .##...##........ */
+ /*03a4:*/ 0x3e,0x00, /* ..#####......... */
+/* --- new character V (86) starting at offset 0x03a6 --- */
+ /*03a6:*/ 10, 10, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03ab:*/ 0xc0,0xc0, /* ##......##...... */
+ /*03ad:*/ 0xc0,0xc0, /* ##......##...... */
+ /*03af:*/ 0x61,0x80, /* .##....##....... */
+ /*03b1:*/ 0x61,0x80, /* .##....##....... */
+ /*03b3:*/ 0x73,0x80, /* .###..###....... */
+ /*03b5:*/ 0x33,0x00, /* ..##..##........ */
+ /*03b7:*/ 0x33,0x00, /* ..##..##........ */
+ /*03b9:*/ 0x1e,0x00, /* ...####......... */
+ /*03bb:*/ 0x1e,0x00, /* ...####......... */
+ /*03bd:*/ 0x0c,0x00, /* ....##.......... */
+ /*03bf:*/ 0x0c,0x00, /* ....##.......... */
+/* --- new character W (87) starting at offset 0x03c1 --- */
+ /*03c1:*/ 14, 14, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03c6:*/ 0xc3,0x0c, /* ##....##....##.. */
+ /*03c8:*/ 0xc3,0x0c, /* ##....##....##.. */
+ /*03ca:*/ 0xc3,0x0c, /* ##....##....##.. */
+ /*03cc:*/ 0x67,0x98, /* .##..####..##... */
+ /*03ce:*/ 0x64,0x98, /* .##..#..#..##... */
+ /*03d0:*/ 0x64,0x98, /* .##..#..#..##... */
+ /*03d2:*/ 0x6c,0xd8, /* .##.##..##.##... */
+ /*03d4:*/ 0x2c,0xd0, /* ..#.##..##.#.... */
+ /*03d6:*/ 0x38,0x70, /* ..###....###.... */
+ /*03d8:*/ 0x18,0x60, /* ...##....##..... */
+ /*03da:*/ 0x18,0x60, /* ...##....##..... */
+/* --- new character X (88) starting at offset 0x03dc --- */
+ /*03dc:*/ 9, 9, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03e1:*/ 0xc1,0x80, /* ##.....##....... */
+ /*03e3:*/ 0xc1,0x80, /* ##.....##....... */
+ /*03e5:*/ 0x63,0x00, /* .##...##........ */
+ /*03e7:*/ 0x36,0x00, /* ..##.##......... */
+ /*03e9:*/ 0x1c,0x00, /* ...###.......... */
+ /*03eb:*/ 0x1c,0x00, /* ...###.......... */
+ /*03ed:*/ 0x36,0x00, /* ..##.##......... */
+ /*03ef:*/ 0x63,0x00, /* .##...##........ */
+ /*03f1:*/ 0x63,0x00, /* .##...##........ */
+ /*03f3:*/ 0xc1,0x80, /* ##.....##....... */
+ /*03f5:*/ 0xc1,0x80, /* ##.....##....... */
+/* --- new character Y (89) starting at offset 0x03f7 --- */
+ /*03f7:*/ 10, 10, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03fc:*/ 0xc0,0xc0, /* ##......##...... */
+ /*03fe:*/ 0x61,0x80, /* .##....##....... */
+ /*0400:*/ 0x61,0x80, /* .##....##....... */
+ /*0402:*/ 0x33,0x00, /* ..##..##........ */
+ /*0404:*/ 0x33,0x00, /* ..##..##........ */
+ /*0406:*/ 0x1e,0x00, /* ...####......... */
+ /*0408:*/ 0x1e,0x00, /* ...####......... */
+ /*040a:*/ 0x0c,0x00, /* ....##.......... */
+ /*040c:*/ 0x0c,0x00, /* ....##.......... */
+ /*040e:*/ 0x0c,0x00, /* ....##.......... */
+ /*0410:*/ 0x0c,0x00, /* ....##.......... */
+/* --- new character Z (90) starting at offset 0x0412 --- */
+ /*0412:*/ 9, 8, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0417:*/ 0xff, /* ######## */
+ /*0418:*/ 0x03, /* ......## */
+ /*0419:*/ 0x06, /* .....##. */
+ /*041a:*/ 0x0c, /* ....##.. */
+ /*041b:*/ 0x1c, /* ...###.. */
+ /*041c:*/ 0x18, /* ...##... */
+ /*041d:*/ 0x30, /* ..##.... */
+ /*041e:*/ 0x70, /* .###.... */
+ /*041f:*/ 0x60, /* .##..... */
+ /*0420:*/ 0xc0, /* ##...... */
+ /*0421:*/ 0xff, /* ######## */
+/* --- new character bracketleft (91) starting at offset 0x0422 --- */
+ /*0422:*/ 5, 4, 14, 1, -3, /* width and bbox (w,h,x,y) */
+ /*0427:*/ 0xf0, /* ####.... */
+ /*0428:*/ 0xc0, /* ##...... */
+ /*0429:*/ 0xc0, /* ##...... */
+ /*042a:*/ 0xc0, /* ##...... */
+ /*042b:*/ 0xc0, /* ##...... */
+ /*042c:*/ 0xc0, /* ##...... */
+ /*042d:*/ 0xc0, /* ##...... */
+ /*042e:*/ 0xc0, /* ##...... */
+ /*042f:*/ 0xc0, /* ##...... */
+ /*0430:*/ 0xc0, /* ##...... */
+ /*0431:*/ 0xc0, /* ##...... */
+ /*0432:*/ 0xc0, /* ##...... */
+ /*0433:*/ 0xc0, /* ##...... */
+ /*0434:*/ 0xf0, /* ####.... */
+/* --- new character backslash (92) starting at offset 0x0435 --- */
+ /*0435:*/ 4, 4, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*043a:*/ 0xc0, /* ##...... */
+ /*043b:*/ 0xc0, /* ##...... */
+ /*043c:*/ 0xc0, /* ##...... */
+ /*043d:*/ 0x40, /* .#...... */
+ /*043e:*/ 0x60, /* .##..... */
+ /*043f:*/ 0x60, /* .##..... */
+ /*0440:*/ 0x60, /* .##..... */
+ /*0441:*/ 0x20, /* ..#..... */
+ /*0442:*/ 0x30, /* ..##.... */
+ /*0443:*/ 0x30, /* ..##.... */
+ /*0444:*/ 0x30, /* ..##.... */
+/* --- new character bracketright (93) starting at offset 0x0445 --- */
+ /*0445:*/ 5, 4, 14, 0, -3, /* width and bbox (w,h,x,y) */
+ /*044a:*/ 0xf0, /* ####.... */
+ /*044b:*/ 0x30, /* ..##.... */
+ /*044c:*/ 0x30, /* ..##.... */
+ /*044d:*/ 0x30, /* ..##.... */
+ /*044e:*/ 0x30, /* ..##.... */
+ /*044f:*/ 0x30, /* ..##.... */
+ /*0450:*/ 0x30, /* ..##.... */
+ /*0451:*/ 0x30, /* ..##.... */
+ /*0452:*/ 0x30, /* ..##.... */
+ /*0453:*/ 0x30, /* ..##.... */
+ /*0454:*/ 0x30, /* ..##.... */
+ /*0455:*/ 0x30, /* ..##.... */
+ /*0456:*/ 0x30, /* ..##.... */
+ /*0457:*/ 0xf0, /* ####.... */
+/* --- new character asciicircum (94) starting at offset 0x0458 --- */
+ /*0458:*/ 8, 6, 4, 1, 7, /* width and bbox (w,h,x,y) */
+ /*045d:*/ 0x30, /* ..##.... */
+ /*045e:*/ 0x78, /* .####... */
+ /*045f:*/ 0xcc, /* ##..##.. */
+ /*0460:*/ 0x84, /* #....#.. */
+/* --- new character underscore (95) starting at offset 0x0461 --- */
+ /*0461:*/ 8, 8, 1, 0, -3, /* width and bbox (w,h,x,y) */
+ /*0466:*/ 0xff, /* ######## */
+/* --- new character grave (96) starting at offset 0x0467 --- */
+ /*0467:*/ 5, 3, 2, 1, 9, /* width and bbox (w,h,x,y) */
+ /*046c:*/ 0xc0, /* ##...... */
+ /*046d:*/ 0x60, /* .##..... */
+/* --- new character a (97) starting at offset 0x046e --- */
+ /*046e:*/ 8, 7, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0473:*/ 0x78, /* .####... */
+ /*0474:*/ 0xcc, /* ##..##.. */
+ /*0475:*/ 0x0c, /* ....##.. */
+ /*0476:*/ 0x7c, /* .#####.. */
+ /*0477:*/ 0xcc, /* ##..##.. */
+ /*0478:*/ 0xcc, /* ##..##.. */
+ /*0479:*/ 0xfc, /* ######.. */
+ /*047a:*/ 0x76, /* .###.##. */
+/* --- new character b (98) starting at offset 0x047b --- */
+ /*047b:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0480:*/ 0xc0, /* ##...... */
+ /*0481:*/ 0xc0, /* ##...... */
+ /*0482:*/ 0xc0, /* ##...... */
+ /*0483:*/ 0xf8, /* #####... */
+ /*0484:*/ 0xec, /* ###.##.. */
+ /*0485:*/ 0xc6, /* ##...##. */
+ /*0486:*/ 0xc6, /* ##...##. */
+ /*0487:*/ 0xc6, /* ##...##. */
+ /*0488:*/ 0xc6, /* ##...##. */
+ /*0489:*/ 0xec, /* ###.##.. */
+ /*048a:*/ 0xd8, /* ##.##... */
+/* --- new character c (99) starting at offset 0x048b --- */
+ /*048b:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0490:*/ 0x38, /* ..###... */
+ /*0491:*/ 0x7c, /* .#####.. */
+ /*0492:*/ 0xc4, /* ##...#.. */
+ /*0493:*/ 0xc0, /* ##...... */
+ /*0494:*/ 0xc0, /* ##...... */
+ /*0495:*/ 0xc4, /* ##...#.. */
+ /*0496:*/ 0x7c, /* .#####.. */
+ /*0497:*/ 0x38, /* ..###... */
+/* --- new character d (100) starting at offset 0x0498 --- */
+ /*0498:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*049d:*/ 0x06, /* .....##. */
+ /*049e:*/ 0x06, /* .....##. */
+ /*049f:*/ 0x06, /* .....##. */
+ /*04a0:*/ 0x3e, /* ..#####. */
+ /*04a1:*/ 0x6e, /* .##.###. */
+ /*04a2:*/ 0xc6, /* ##...##. */
+ /*04a3:*/ 0xc6, /* ##...##. */
+ /*04a4:*/ 0xc6, /* ##...##. */
+ /*04a5:*/ 0xc6, /* ##...##. */
+ /*04a6:*/ 0x6e, /* .##.###. */
+ /*04a7:*/ 0x36, /* ..##.##. */
+/* --- new character e (101) starting at offset 0x04a8 --- */
+ /*04a8:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04ad:*/ 0x78, /* .####... */
+ /*04ae:*/ 0xcc, /* ##..##.. */
+ /*04af:*/ 0xcc, /* ##..##.. */
+ /*04b0:*/ 0xfc, /* ######.. */
+ /*04b1:*/ 0xc0, /* ##...... */
+ /*04b2:*/ 0xc0, /* ##...... */
+ /*04b3:*/ 0xec, /* ###.##.. */
+ /*04b4:*/ 0x78, /* .####... */
+/* --- new character f (102) starting at offset 0x04b5 --- */
+ /*04b5:*/ 4, 5, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*04ba:*/ 0x38, /* ..###... */
+ /*04bb:*/ 0x60, /* .##..... */
+ /*04bc:*/ 0x60, /* .##..... */
+ /*04bd:*/ 0xf0, /* ####.... */
+ /*04be:*/ 0x60, /* .##..... */
+ /*04bf:*/ 0x60, /* .##..... */
+ /*04c0:*/ 0x60, /* .##..... */
+ /*04c1:*/ 0x60, /* .##..... */
+ /*04c2:*/ 0x60, /* .##..... */
+ /*04c3:*/ 0x60, /* .##..... */
+ /*04c4:*/ 0x60, /* .##..... */
+/* --- new character g (103) starting at offset 0x04c5 --- */
+ /*04c5:*/ 9, 7, 11, 1, -3, /* width and bbox (w,h,x,y) */
+ /*04ca:*/ 0x3a, /* ..###.#. */
+ /*04cb:*/ 0x6e, /* .##.###. */
+ /*04cc:*/ 0xc6, /* ##...##. */
+ /*04cd:*/ 0xc6, /* ##...##. */
+ /*04ce:*/ 0xc6, /* ##...##. */
+ /*04cf:*/ 0xc6, /* ##...##. */
+ /*04d0:*/ 0x6e, /* .##.###. */
+ /*04d1:*/ 0x3e, /* ..#####. */
+ /*04d2:*/ 0x06, /* .....##. */
+ /*04d3:*/ 0xce, /* ##..###. */
+ /*04d4:*/ 0x7c, /* .#####.. */
+/* --- new character h (104) starting at offset 0x04d5 --- */
+ /*04d5:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04da:*/ 0xc0, /* ##...... */
+ /*04db:*/ 0xc0, /* ##...... */
+ /*04dc:*/ 0xc0, /* ##...... */
+ /*04dd:*/ 0xdc, /* ##.###.. */
+ /*04de:*/ 0xee, /* ###.###. */
+ /*04df:*/ 0xc6, /* ##...##. */
+ /*04e0:*/ 0xc6, /* ##...##. */
+ /*04e1:*/ 0xc6, /* ##...##. */
+ /*04e2:*/ 0xc6, /* ##...##. */
+ /*04e3:*/ 0xc6, /* ##...##. */
+ /*04e4:*/ 0xc6, /* ##...##. */
+/* --- new character i (105) starting at offset 0x04e5 --- */
+ /*04e5:*/ 4, 2, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04ea:*/ 0xc0, /* ##...... */
+ /*04eb:*/ 0xc0, /* ##...... */
+ /*04ec:*/ 0x00, /* ........ */
+ /*04ed:*/ 0xc0, /* ##...... */
+ /*04ee:*/ 0xc0, /* ##...... */
+ /*04ef:*/ 0xc0, /* ##...... */
+ /*04f0:*/ 0xc0, /* ##...... */
+ /*04f1:*/ 0xc0, /* ##...... */
+ /*04f2:*/ 0xc0, /* ##...... */
+ /*04f3:*/ 0xc0, /* ##...... */
+ /*04f4:*/ 0xc0, /* ##...... */
+/* --- new character j (106) starting at offset 0x04f5 --- */
+ /*04f5:*/ 4, 3, 14, 0, -3, /* width and bbox (w,h,x,y) */
+ /*04fa:*/ 0x60, /* .##..... */
+ /*04fb:*/ 0x60, /* .##..... */
+ /*04fc:*/ 0x00, /* ........ */
+ /*04fd:*/ 0x60, /* .##..... */
+ /*04fe:*/ 0x60, /* .##..... */
+ /*04ff:*/ 0x60, /* .##..... */
+ /*0500:*/ 0x60, /* .##..... */
+ /*0501:*/ 0x60, /* .##..... */
+ /*0502:*/ 0x60, /* .##..... */
+ /*0503:*/ 0x60, /* .##..... */
+ /*0504:*/ 0x60, /* .##..... */
+ /*0505:*/ 0x60, /* .##..... */
+ /*0506:*/ 0xe0, /* ###..... */
+ /*0507:*/ 0xc0, /* ##...... */
+/* --- new character k (107) starting at offset 0x0508 --- */
+ /*0508:*/ 8, 6, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*050d:*/ 0xc0, /* ##...... */
+ /*050e:*/ 0xc0, /* ##...... */
+ /*050f:*/ 0xc0, /* ##...... */
+ /*0510:*/ 0xcc, /* ##..##.. */
+ /*0511:*/ 0xd8, /* ##.##... */
+ /*0512:*/ 0xf0, /* ####.... */
+ /*0513:*/ 0xf0, /* ####.... */
+ /*0514:*/ 0xd8, /* ##.##... */
+ /*0515:*/ 0xd8, /* ##.##... */
+ /*0516:*/ 0xcc, /* ##..##.. */
+ /*0517:*/ 0xcc, /* ##..##.. */
+/* --- new character l (108) starting at offset 0x0518 --- */
+ /*0518:*/ 4, 2, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*051d:*/ 0xc0, /* ##...... */
+ /*051e:*/ 0xc0, /* ##...... */
+ /*051f:*/ 0xc0, /* ##...... */
+ /*0520:*/ 0xc0, /* ##...... */
+ /*0521:*/ 0xc0, /* ##...... */
+ /*0522:*/ 0xc0, /* ##...... */
+ /*0523:*/ 0xc0, /* ##...... */
+ /*0524:*/ 0xc0, /* ##...... */
+ /*0525:*/ 0xc0, /* ##...... */
+ /*0526:*/ 0xc0, /* ##...... */
+ /*0527:*/ 0xc0, /* ##...... */
+/* --- new character m (109) starting at offset 0x0528 --- */
+ /*0528:*/ 12, 10, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*052d:*/ 0xdb,0x80, /* ##.##.###....... */
+ /*052f:*/ 0xee,0xc0, /* ###.###.##...... */
+ /*0531:*/ 0xcc,0xc0, /* ##..##..##...... */
+ /*0533:*/ 0xcc,0xc0, /* ##..##..##...... */
+ /*0535:*/ 0xcc,0xc0, /* ##..##..##...... */
+ /*0537:*/ 0xcc,0xc0, /* ##..##..##...... */
+ /*0539:*/ 0xcc,0xc0, /* ##..##..##...... */
+ /*053b:*/ 0xcc,0xc0, /* ##..##..##...... */
+/* --- new character n (110) starting at offset 0x053d --- */
+ /*053d:*/ 9, 7, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0542:*/ 0xdc, /* ##.###.. */
+ /*0543:*/ 0xee, /* ###.###. */
+ /*0544:*/ 0xc6, /* ##...##. */
+ /*0545:*/ 0xc6, /* ##...##. */
+ /*0546:*/ 0xc6, /* ##...##. */
+ /*0547:*/ 0xc6, /* ##...##. */
+ /*0548:*/ 0xc6, /* ##...##. */
+ /*0549:*/ 0xc6, /* ##...##. */
+/* --- new character o (111) starting at offset 0x054a --- */
+ /*054a:*/ 9, 7, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*054f:*/ 0x38, /* ..###... */
+ /*0550:*/ 0x6c, /* .##.##.. */
+ /*0551:*/ 0xc6, /* ##...##. */
+ /*0552:*/ 0xc6, /* ##...##. */
+ /*0553:*/ 0xc6, /* ##...##. */
+ /*0554:*/ 0xc6, /* ##...##. */
+ /*0555:*/ 0x6c, /* .##.##.. */
+ /*0556:*/ 0x38, /* ..###... */
+/* --- new character p (112) starting at offset 0x0557 --- */
+ /*0557:*/ 9, 7, 11, 1, -3, /* width and bbox (w,h,x,y) */
+ /*055c:*/ 0xd8, /* ##.##... */
+ /*055d:*/ 0xec, /* ###.##.. */
+ /*055e:*/ 0xc6, /* ##...##. */
+ /*055f:*/ 0xc6, /* ##...##. */
+ /*0560:*/ 0xc6, /* ##...##. */
+ /*0561:*/ 0xc6, /* ##...##. */
+ /*0562:*/ 0xec, /* ###.##.. */
+ /*0563:*/ 0xf8, /* #####... */
+ /*0564:*/ 0xc0, /* ##...... */
+ /*0565:*/ 0xc0, /* ##...... */
+ /*0566:*/ 0xc0, /* ##...... */
+/* --- new character q (113) starting at offset 0x0567 --- */
+ /*0567:*/ 9, 7, 11, 1, -3, /* width and bbox (w,h,x,y) */
+ /*056c:*/ 0x36, /* ..##.##. */
+ /*056d:*/ 0x6e, /* .##.###. */
+ /*056e:*/ 0xc6, /* ##...##. */
+ /*056f:*/ 0xc6, /* ##...##. */
+ /*0570:*/ 0xc6, /* ##...##. */
+ /*0571:*/ 0xc6, /* ##...##. */
+ /*0572:*/ 0x6e, /* .##.###. */
+ /*0573:*/ 0x3e, /* ..#####. */
+ /*0574:*/ 0x06, /* .....##. */
+ /*0575:*/ 0x06, /* .....##. */
+ /*0576:*/ 0x06, /* .....##. */
+/* --- new character r (114) starting at offset 0x0577 --- */
+ /*0577:*/ 6, 5, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*057c:*/ 0xd8, /* ##.##... */
+ /*057d:*/ 0xf8, /* #####... */
+ /*057e:*/ 0xc0, /* ##...... */
+ /*057f:*/ 0xc0, /* ##...... */
+ /*0580:*/ 0xc0, /* ##...... */
+ /*0581:*/ 0xc0, /* ##...... */
+ /*0582:*/ 0xc0, /* ##...... */
+ /*0583:*/ 0xc0, /* ##...... */
+/* --- new character s (115) starting at offset 0x0584 --- */
+ /*0584:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0589:*/ 0x78, /* .####... */
+ /*058a:*/ 0xec, /* ###.##.. */
+ /*058b:*/ 0xc0, /* ##...... */
+ /*058c:*/ 0x78, /* .####... */
+ /*058d:*/ 0x1c, /* ...###.. */
+ /*058e:*/ 0x0c, /* ....##.. */
+ /*058f:*/ 0xec, /* ###.##.. */
+ /*0590:*/ 0x78, /* .####... */
+/* --- new character t (116) starting at offset 0x0591 --- */
+ /*0591:*/ 5, 5, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0596:*/ 0x60, /* .##..... */
+ /*0597:*/ 0x60, /* .##..... */
+ /*0598:*/ 0xf8, /* #####... */
+ /*0599:*/ 0x60, /* .##..... */
+ /*059a:*/ 0x60, /* .##..... */
+ /*059b:*/ 0x60, /* .##..... */
+ /*059c:*/ 0x60, /* .##..... */
+ /*059d:*/ 0x60, /* .##..... */
+ /*059e:*/ 0x68, /* .##.#... */
+ /*059f:*/ 0x30, /* ..##.... */
+/* --- new character u (117) starting at offset 0x05a0 --- */
+ /*05a0:*/ 9, 7, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*05a5:*/ 0xc6, /* ##...##. */
+ /*05a6:*/ 0xc6, /* ##...##. */
+ /*05a7:*/ 0xc6, /* ##...##. */
+ /*05a8:*/ 0xc6, /* ##...##. */
+ /*05a9:*/ 0xc6, /* ##...##. */
+ /*05aa:*/ 0xc6, /* ##...##. */
+ /*05ab:*/ 0xee, /* ###.###. */
+ /*05ac:*/ 0x76, /* .###.##. */
+/* --- new character v (118) starting at offset 0x05ad --- */
+ /*05ad:*/ 8, 8, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*05b2:*/ 0xc3, /* ##....## */
+ /*05b3:*/ 0xc3, /* ##....## */
+ /*05b4:*/ 0x66, /* .##..##. */
+ /*05b5:*/ 0x66, /* .##..##. */
+ /*05b6:*/ 0x24, /* ..#..#.. */
+ /*05b7:*/ 0x3c, /* ..####.. */
+ /*05b8:*/ 0x18, /* ...##... */
+ /*05b9:*/ 0x18, /* ...##... */
+/* --- new character w (119) starting at offset 0x05ba --- */
+ /*05ba:*/ 10, 10, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*05bf:*/ 0xcc,0xc0, /* ##..##..##...... */
+ /*05c1:*/ 0xcc,0xc0, /* ##..##..##...... */
+ /*05c3:*/ 0xcc,0xc0, /* ##..##..##...... */
+ /*05c5:*/ 0x6d,0x80, /* .##.##.##....... */
+ /*05c7:*/ 0x6d,0x80, /* .##.##.##....... */
+ /*05c9:*/ 0x33,0x00, /* ..##..##........ */
+ /*05cb:*/ 0x33,0x00, /* ..##..##........ */
+ /*05cd:*/ 0x33,0x00, /* ..##..##........ */
+/* --- new character x (120) starting at offset 0x05cf --- */
+ /*05cf:*/ 7, 7, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*05d4:*/ 0xc6, /* ##...##. */
+ /*05d5:*/ 0xc6, /* ##...##. */
+ /*05d6:*/ 0x6c, /* .##.##.. */
+ /*05d7:*/ 0x38, /* ..###... */
+ /*05d8:*/ 0x38, /* ..###... */
+ /*05d9:*/ 0x6c, /* .##.##.. */
+ /*05da:*/ 0xc6, /* ##...##. */
+ /*05db:*/ 0xc6, /* ##...##. */
+/* --- new character y (121) starting at offset 0x05dc --- */
+ /*05dc:*/ 8, 8, 11, 0, -3, /* width and bbox (w,h,x,y) */
+ /*05e1:*/ 0xc3, /* ##....## */
+ /*05e2:*/ 0xc3, /* ##....## */
+ /*05e3:*/ 0x66, /* .##..##. */
+ /*05e4:*/ 0x66, /* .##..##. */
+ /*05e5:*/ 0x24, /* ..#..#.. */
+ /*05e6:*/ 0x3c, /* ..####.. */
+ /*05e7:*/ 0x18, /* ...##... */
+ /*05e8:*/ 0x18, /* ...##... */
+ /*05e9:*/ 0x18, /* ...##... */
+ /*05ea:*/ 0x30, /* ..##.... */
+ /*05eb:*/ 0x70, /* .###.... */
+/* --- new character z (122) starting at offset 0x05ec --- */
+ /*05ec:*/ 6, 6, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*05f1:*/ 0xfc, /* ######.. */
+ /*05f2:*/ 0x0c, /* ....##.. */
+ /*05f3:*/ 0x18, /* ...##... */
+ /*05f4:*/ 0x30, /* ..##.... */
+ /*05f5:*/ 0x30, /* ..##.... */
+ /*05f6:*/ 0x60, /* .##..... */
+ /*05f7:*/ 0xc0, /* ##...... */
+ /*05f8:*/ 0xfc, /* ######.. */
+/* --- new character braceleft (123) starting at offset 0x05f9 --- */
+ /*05f9:*/ 6, 5, 14, 0, -3, /* width and bbox (w,h,x,y) */
+ /*05fe:*/ 0x18, /* ...##... */
+ /*05ff:*/ 0x30, /* ..##.... */
+ /*0600:*/ 0x30, /* ..##.... */
+ /*0601:*/ 0x30, /* ..##.... */
+ /*0602:*/ 0x30, /* ..##.... */
+ /*0603:*/ 0x60, /* .##..... */
+ /*0604:*/ 0xc0, /* ##...... */
+ /*0605:*/ 0x60, /* .##..... */
+ /*0606:*/ 0x30, /* ..##.... */
+ /*0607:*/ 0x30, /* ..##.... */
+ /*0608:*/ 0x30, /* ..##.... */
+ /*0609:*/ 0x30, /* ..##.... */
+ /*060a:*/ 0x30, /* ..##.... */
+ /*060b:*/ 0x18, /* ...##... */
+/* --- new character bar (124) starting at offset 0x060c --- */
+ /*060c:*/ 4, 2, 14, 1, -3, /* width and bbox (w,h,x,y) */
+ /*0611:*/ 0xc0, /* ##...... */
+ /*0612:*/ 0xc0, /* ##...... */
+ /*0613:*/ 0xc0, /* ##...... */
+ /*0614:*/ 0xc0, /* ##...... */
+ /*0615:*/ 0xc0, /* ##...... */
+ /*0616:*/ 0xc0, /* ##...... */
+ /*0617:*/ 0xc0, /* ##...... */
+ /*0618:*/ 0xc0, /* ##...... */
+ /*0619:*/ 0xc0, /* ##...... */
+ /*061a:*/ 0xc0, /* ##...... */
+ /*061b:*/ 0xc0, /* ##...... */
+ /*061c:*/ 0xc0, /* ##...... */
+ /*061d:*/ 0xc0, /* ##...... */
+ /*061e:*/ 0xc0, /* ##...... */
+/* --- new character braceright (125) starting at offset 0x061f --- */
+ /*061f:*/ 6, 5, 14, 1, -3, /* width and bbox (w,h,x,y) */
+ /*0624:*/ 0xc0, /* ##...... */
+ /*0625:*/ 0x60, /* .##..... */
+ /*0626:*/ 0x60, /* .##..... */
+ /*0627:*/ 0x60, /* .##..... */
+ /*0628:*/ 0x60, /* .##..... */
+ /*0629:*/ 0x30, /* ..##.... */
+ /*062a:*/ 0x18, /* ...##... */
+ /*062b:*/ 0x30, /* ..##.... */
+ /*062c:*/ 0x60, /* .##..... */
+ /*062d:*/ 0x60, /* .##..... */
+ /*062e:*/ 0x60, /* .##..... */
+ /*062f:*/ 0x60, /* .##..... */
+ /*0630:*/ 0x60, /* .##..... */
+ /*0631:*/ 0xc0, /* ##...... */
+/* --- new character asciitilde (126) starting at offset 0x0632 --- */
+ /*0632:*/ 9, 7, 3, 1, 3, /* width and bbox (w,h,x,y) */
+ /*0637:*/ 0x72, /* .###..#. */
+ /*0638:*/ 0xde, /* ##.####. */
+ /*0639:*/ 0x8c, /* #...##.. */
+};
+static const uint16_t font_helvB14_offsets[] = {
+0x0000 /* space */,
+ 0x0006 /* exclam */,
+ 0x0016 /* quotedbl */,
+ 0x001e /* numbersign */,
+ 0x0037 /* dollar */,
+ 0x0049 /* percent */,
+ 0x0062 /* ampersand */,
+ 0x007b /* quotesingle */,
+ 0x0083 /* parenleft */,
+ 0x0096 /* parenright */,
+ 0x00a9 /* asterisk */,
+ 0x00b2 /* plus */,
+ 0x00be /* comma */,
+ 0x00c6 /* hyphen */,
+ 0x00cc /* period */,
+ 0x00d3 /* slash */,
+ 0x00e3 /* zero */,
+ 0x00f2 /* one */,
+ 0x0101 /* two */,
+ 0x0110 /* three */,
+ 0x011f /* four */,
+ 0x012e /* five */,
+ 0x013d /* six */,
+ 0x014c /* seven */,
+ 0x015b /* eight */,
+ 0x016a /* nine */,
+ 0x0179 /* colon */,
+ 0x0186 /* semicolon */,
+ 0x0194 /* less */,
+ 0x019e /* equal */,
+ 0x01a6 /* greater */,
+ 0x01b0 /* question */,
+ 0x01c0 /* at */,
+ 0x01dd /* A */,
+ 0x01f8 /* B */,
+ 0x0208 /* C */,
+ 0x0223 /* D */,
+ 0x023e /* E */,
+ 0x024e /* F */,
+ 0x025e /* G */,
+ 0x0279 /* H */,
+ 0x0289 /* I */,
+ 0x0299 /* J */,
+ 0x02a9 /* K */,
+ 0x02c4 /* L */,
+ 0x02d4 /* M */,
+ 0x02ef /* N */,
+ 0x030a /* O */,
+ 0x0325 /* P */,
+ 0x0335 /* Q */,
+ 0x0350 /* R */,
+ 0x036b /* S */,
+ 0x037b /* T */,
+ 0x038b /* U */,
+ 0x03a6 /* V */,
+ 0x03c1 /* W */,
+ 0x03dc /* X */,
+ 0x03f7 /* Y */,
+ 0x0412 /* Z */,
+ 0x0422 /* bracketleft */,
+ 0x0435 /* backslash */,
+ 0x0445 /* bracketright */,
+ 0x0458 /* asciicircum */,
+ 0x0461 /* underscore */,
+ 0x0467 /* grave */,
+ 0x046e /* a */,
+ 0x047b /* b */,
+ 0x048b /* c */,
+ 0x0498 /* d */,
+ 0x04a8 /* e */,
+ 0x04b5 /* f */,
+ 0x04c5 /* g */,
+ 0x04d5 /* h */,
+ 0x04e5 /* i */,
+ 0x04f5 /* j */,
+ 0x0508 /* k */,
+ 0x0518 /* l */,
+ 0x0528 /* m */,
+ 0x053d /* n */,
+ 0x054a /* o */,
+ 0x0557 /* p */,
+ 0x0567 /* q */,
+ 0x0577 /* r */,
+ 0x0584 /* s */,
+ 0x0591 /* t */,
+ 0x05a0 /* u */,
+ 0x05ad /* v */,
+ 0x05ba /* w */,
+ 0x05cf /* x */,
+ 0x05dc /* y */,
+ 0x05ec /* z */,
+ 0x05f9 /* braceleft */,
+ 0x060c /* bar */,
+ 0x061f /* braceright */,
+ 0x0632 /* asciitilde */,
+ 0xffff /* (no glyph) */
+};
+const struct fb_font font_helvB14 = {
+ .height = 16,
+ .ascent = 13,
+ .firstchar = 32, /* space */
+ .lastchar = 127, /* ? */
+ .chardata = font_helvB14_data,
+ .charoffs = font_helvB14_offsets,
+};
diff --git a/src/target/firmware/fb/helvB24.c b/src/target/firmware/fb/helvB24.c
new file mode 100644
index 00000000..509b9db5
--- /dev/null
+++ b/src/target/firmware/fb/helvB24.c
@@ -0,0 +1,1871 @@
+#include <fb/font.h>
+static const uint8_t font_helvB24_data[] = {
+/* --- new character space (32) starting at offset 0x0000 --- */
+ /*0000:*/ 6, 1, 1, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x00, /* ........ */
+/* --- new character exclam (33) starting at offset 0x0006 --- */
+ /*0006:*/ 7, 3, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*000b:*/ 0xe0, /* ###..... */
+ /*000c:*/ 0xe0, /* ###..... */
+ /*000d:*/ 0xe0, /* ###..... */
+ /*000e:*/ 0xe0, /* ###..... */
+ /*000f:*/ 0xe0, /* ###..... */
+ /*0010:*/ 0xe0, /* ###..... */
+ /*0011:*/ 0xe0, /* ###..... */
+ /*0012:*/ 0xe0, /* ###..... */
+ /*0013:*/ 0xe0, /* ###..... */
+ /*0014:*/ 0xe0, /* ###..... */
+ /*0015:*/ 0xe0, /* ###..... */
+ /*0016:*/ 0xe0, /* ###..... */
+ /*0017:*/ 0xe0, /* ###..... */
+ /*0018:*/ 0xe0, /* ###..... */
+ /*0019:*/ 0x00, /* ........ */
+ /*001a:*/ 0x00, /* ........ */
+ /*001b:*/ 0xe0, /* ###..... */
+ /*001c:*/ 0xe0, /* ###..... */
+ /*001d:*/ 0xe0, /* ###..... */
+/* --- new character quotedbl (34) starting at offset 0x001e --- */
+ /*001e:*/ 9, 5, 6, 2, 13, /* width and bbox (w,h,x,y) */
+ /*0023:*/ 0xd8, /* ##.##... */
+ /*0024:*/ 0xd8, /* ##.##... */
+ /*0025:*/ 0xd8, /* ##.##... */
+ /*0026:*/ 0xd8, /* ##.##... */
+ /*0027:*/ 0xd8, /* ##.##... */
+ /*0028:*/ 0x90, /* #..#.... */
+/* --- new character numbersign (35) starting at offset 0x0029 --- */
+ /*0029:*/ 14, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*002e:*/ 0x0c,0xc0, /* ....##..##...... */
+ /*0030:*/ 0x0c,0xc0, /* ....##..##...... */
+ /*0032:*/ 0x0c,0xc0, /* ....##..##...... */
+ /*0034:*/ 0x0c,0xc0, /* ....##..##...... */
+ /*0036:*/ 0x0c,0xc0, /* ....##..##...... */
+ /*0038:*/ 0x7f,0xf0, /* .###########.... */
+ /*003a:*/ 0x7f,0xf0, /* .###########.... */
+ /*003c:*/ 0x19,0x80, /* ...##..##....... */
+ /*003e:*/ 0x19,0x80, /* ...##..##....... */
+ /*0040:*/ 0x19,0x80, /* ...##..##....... */
+ /*0042:*/ 0x19,0x80, /* ...##..##....... */
+ /*0044:*/ 0xff,0xe0, /* ###########..... */
+ /*0046:*/ 0xff,0xe0, /* ###########..... */
+ /*0048:*/ 0x33,0x00, /* ..##..##........ */
+ /*004a:*/ 0x33,0x00, /* ..##..##........ */
+ /*004c:*/ 0x33,0x00, /* ..##..##........ */
+ /*004e:*/ 0x33,0x00, /* ..##..##........ */
+ /*0050:*/ 0x33,0x00, /* ..##..##........ */
+/* --- new character dollar (36) starting at offset 0x0052 --- */
+ /*0052:*/ 13, 12, 21, 0, -2, /* width and bbox (w,h,x,y) */
+ /*0057:*/ 0x06,0x00, /* .....##......... */
+ /*0059:*/ 0x3f,0x80, /* ..#######....... */
+ /*005b:*/ 0x7f,0xc0, /* .#########...... */
+ /*005d:*/ 0xf6,0xe0, /* ####.##.###..... */
+ /*005f:*/ 0xe6,0xe0, /* ###..##.###..... */
+ /*0061:*/ 0xe6,0xe0, /* ###..##.###..... */
+ /*0063:*/ 0xf6,0x00, /* ####.##......... */
+ /*0065:*/ 0x7e,0x00, /* .######......... */
+ /*0067:*/ 0x3e,0x00, /* ..#####......... */
+ /*0069:*/ 0x0f,0x00, /* ....####........ */
+ /*006b:*/ 0x07,0xc0, /* .....#####...... */
+ /*006d:*/ 0x07,0xe0, /* .....######..... */
+ /*006f:*/ 0x06,0xf0, /* .....##.####.... */
+ /*0071:*/ 0xe6,0x70, /* ###..##..###.... */
+ /*0073:*/ 0xe6,0x70, /* ###..##..###.... */
+ /*0075:*/ 0xe6,0x70, /* ###..##..###.... */
+ /*0077:*/ 0xf6,0xf0, /* ####.##.####.... */
+ /*0079:*/ 0x7f,0xe0, /* .##########..... */
+ /*007b:*/ 0x1f,0xc0, /* ...#######...... */
+ /*007d:*/ 0x06,0x00, /* .....##......... */
+ /*007f:*/ 0x06,0x00, /* .....##......... */
+/* --- new character percent (37) starting at offset 0x0081 --- */
+ /*0081:*/ 22, 21, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0086:*/ 0x00,0x07,0x00, /* .............###........ */
+ /*0089:*/ 0x3e,0x07,0x00, /* ..#####......###........ */
+ /*008c:*/ 0x7f,0x0e,0x00, /* .#######....###......... */
+ /*008f:*/ 0xe3,0x8e,0x00, /* ###...###...###......... */
+ /*0092:*/ 0xc1,0x9c,0x00, /* ##.....##..###.......... */
+ /*0095:*/ 0xc1,0x9c,0x00, /* ##.....##..###.......... */
+ /*0098:*/ 0xe3,0xb8,0x00, /* ###...###.###........... */
+ /*009b:*/ 0x7f,0x38,0x00, /* .#######..###........... */
+ /*009e:*/ 0x3e,0x70,0x00, /* ..#####..###............ */
+ /*00a1:*/ 0x00,0x70,0x00, /* .........###............ */
+ /*00a4:*/ 0x00,0xe3,0xe0, /* ........###...#####..... */
+ /*00a7:*/ 0x00,0xe7,0xf0, /* ........###..#######.... */
+ /*00aa:*/ 0x01,0xce,0x38, /* .......###..###...###... */
+ /*00ad:*/ 0x01,0xcc,0x18, /* .......###..##.....##... */
+ /*00b0:*/ 0x03,0x8c,0x18, /* ......###...##.....##... */
+ /*00b3:*/ 0x03,0x8e,0x38, /* ......###...###...###... */
+ /*00b6:*/ 0x07,0x07,0xf0, /* .....###.....#######.... */
+ /*00b9:*/ 0x07,0x03,0xe0, /* .....###......#####..... */
+/* --- new character ampersand (38) starting at offset 0x00bc --- */
+ /*00bc:*/ 18, 16, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00c1:*/ 0x0f,0x80, /* ....#####....... */
+ /*00c3:*/ 0x1f,0xc0, /* ...#######...... */
+ /*00c5:*/ 0x3d,0xe0, /* ..####.####..... */
+ /*00c7:*/ 0x38,0xe0, /* ..###...###..... */
+ /*00c9:*/ 0x38,0xe0, /* ..###...###..... */
+ /*00cb:*/ 0x38,0xe0, /* ..###...###..... */
+ /*00cd:*/ 0x1d,0xc0, /* ...###.###...... */
+ /*00cf:*/ 0x0f,0x80, /* ....#####....... */
+ /*00d1:*/ 0x1f,0x00, /* ...#####........ */
+ /*00d3:*/ 0x3f,0x9c, /* ..#######..###.. */
+ /*00d5:*/ 0x7b,0xdc, /* .####.####.###.. */
+ /*00d7:*/ 0x71,0xfc, /* .###...#######.. */
+ /*00d9:*/ 0xe0,0xf8, /* ###.....#####... */
+ /*00db:*/ 0xe0,0x70, /* ###......###.... */
+ /*00dd:*/ 0xe0,0xf8, /* ###.....#####... */
+ /*00df:*/ 0xf1,0xfc, /* ####...#######.. */
+ /*00e1:*/ 0x7f,0xce, /* .#########..###. */
+ /*00e3:*/ 0x1f,0x87, /* ...######....### */
+/* --- new character quotesingle (39) starting at offset 0x00e5 --- */
+ /*00e5:*/ 6, 2, 6, 2, 13, /* width and bbox (w,h,x,y) */
+ /*00ea:*/ 0xc0, /* ##...... */
+ /*00eb:*/ 0xc0, /* ##...... */
+ /*00ec:*/ 0xc0, /* ##...... */
+ /*00ed:*/ 0xc0, /* ##...... */
+ /*00ee:*/ 0xc0, /* ##...... */
+ /*00ef:*/ 0x80, /* #....... */
+/* --- new character parenleft (40) starting at offset 0x00f0 --- */
+ /*00f0:*/ 8, 6, 24, 1, -5, /* width and bbox (w,h,x,y) */
+ /*00f5:*/ 0x0c, /* ....##.. */
+ /*00f6:*/ 0x1c, /* ...###.. */
+ /*00f7:*/ 0x38, /* ..###... */
+ /*00f8:*/ 0x38, /* ..###... */
+ /*00f9:*/ 0x70, /* .###.... */
+ /*00fa:*/ 0x70, /* .###.... */
+ /*00fb:*/ 0x60, /* .##..... */
+ /*00fc:*/ 0xe0, /* ###..... */
+ /*00fd:*/ 0xe0, /* ###..... */
+ /*00fe:*/ 0xe0, /* ###..... */
+ /*00ff:*/ 0xe0, /* ###..... */
+ /*0100:*/ 0xe0, /* ###..... */
+ /*0101:*/ 0xe0, /* ###..... */
+ /*0102:*/ 0xe0, /* ###..... */
+ /*0103:*/ 0xe0, /* ###..... */
+ /*0104:*/ 0xe0, /* ###..... */
+ /*0105:*/ 0xe0, /* ###..... */
+ /*0106:*/ 0x60, /* .##..... */
+ /*0107:*/ 0x70, /* .###.... */
+ /*0108:*/ 0x70, /* .###.... */
+ /*0109:*/ 0x38, /* ..###... */
+ /*010a:*/ 0x38, /* ..###... */
+ /*010b:*/ 0x1c, /* ...###.. */
+ /*010c:*/ 0x0c, /* ....##.. */
+/* --- new character parenright (41) starting at offset 0x010d --- */
+ /*010d:*/ 8, 6, 24, 1, -5, /* width and bbox (w,h,x,y) */
+ /*0112:*/ 0xc0, /* ##...... */
+ /*0113:*/ 0xe0, /* ###..... */
+ /*0114:*/ 0x70, /* .###.... */
+ /*0115:*/ 0x70, /* .###.... */
+ /*0116:*/ 0x38, /* ..###... */
+ /*0117:*/ 0x38, /* ..###... */
+ /*0118:*/ 0x18, /* ...##... */
+ /*0119:*/ 0x1c, /* ...###.. */
+ /*011a:*/ 0x1c, /* ...###.. */
+ /*011b:*/ 0x1c, /* ...###.. */
+ /*011c:*/ 0x1c, /* ...###.. */
+ /*011d:*/ 0x1c, /* ...###.. */
+ /*011e:*/ 0x1c, /* ...###.. */
+ /*011f:*/ 0x1c, /* ...###.. */
+ /*0120:*/ 0x1c, /* ...###.. */
+ /*0121:*/ 0x1c, /* ...###.. */
+ /*0122:*/ 0x1c, /* ...###.. */
+ /*0123:*/ 0x18, /* ...##... */
+ /*0124:*/ 0x38, /* ..###... */
+ /*0125:*/ 0x38, /* ..###... */
+ /*0126:*/ 0x70, /* .###.... */
+ /*0127:*/ 0x70, /* .###.... */
+ /*0128:*/ 0xe0, /* ###..... */
+ /*0129:*/ 0xc0, /* ##...... */
+/* --- new character asterisk (42) starting at offset 0x012a --- */
+ /*012a:*/ 10, 8, 7, 1, 12, /* width and bbox (w,h,x,y) */
+ /*012f:*/ 0x18, /* ...##... */
+ /*0130:*/ 0x18, /* ...##... */
+ /*0131:*/ 0xdb, /* ##.##.## */
+ /*0132:*/ 0xff, /* ######## */
+ /*0133:*/ 0x3c, /* ..####.. */
+ /*0134:*/ 0x66, /* .##..##. */
+ /*0135:*/ 0x66, /* .##..##. */
+/* --- new character plus (43) starting at offset 0x0136 --- */
+ /*0136:*/ 15, 11, 12, 2, 1, /* width and bbox (w,h,x,y) */
+ /*013b:*/ 0x0e,0x00, /* ....###......... */
+ /*013d:*/ 0x0e,0x00, /* ....###......... */
+ /*013f:*/ 0x0e,0x00, /* ....###......... */
+ /*0141:*/ 0x0e,0x00, /* ....###......... */
+ /*0143:*/ 0x0e,0x00, /* ....###......... */
+ /*0145:*/ 0xff,0xe0, /* ###########..... */
+ /*0147:*/ 0xff,0xe0, /* ###########..... */
+ /*0149:*/ 0x0e,0x00, /* ....###......... */
+ /*014b:*/ 0x0e,0x00, /* ....###......... */
+ /*014d:*/ 0x0e,0x00, /* ....###......... */
+ /*014f:*/ 0x0e,0x00, /* ....###......... */
+ /*0151:*/ 0x0e,0x00, /* ....###......... */
+/* --- new character comma (44) starting at offset 0x0153 --- */
+ /*0153:*/ 7, 3, 6, 2, -3, /* width and bbox (w,h,x,y) */
+ /*0158:*/ 0xe0, /* ###..... */
+ /*0159:*/ 0xe0, /* ###..... */
+ /*015a:*/ 0xe0, /* ###..... */
+ /*015b:*/ 0x60, /* .##..... */
+ /*015c:*/ 0x60, /* .##..... */
+ /*015d:*/ 0xc0, /* ##...... */
+/* --- new character hyphen (45) starting at offset 0x015e --- */
+ /*015e:*/ 8, 7, 3, 0, 6, /* width and bbox (w,h,x,y) */
+ /*0163:*/ 0xfe, /* #######. */
+ /*0164:*/ 0xfe, /* #######. */
+ /*0165:*/ 0xfe, /* #######. */
+/* --- new character period (46) starting at offset 0x0166 --- */
+ /*0166:*/ 7, 3, 3, 2, 0, /* width and bbox (w,h,x,y) */
+ /*016b:*/ 0xe0, /* ###..... */
+ /*016c:*/ 0xe0, /* ###..... */
+ /*016d:*/ 0xe0, /* ###..... */
+/* --- new character slash (47) starting at offset 0x016e --- */
+ /*016e:*/ 8, 8, 19, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0173:*/ 0x07, /* .....### */
+ /*0174:*/ 0x07, /* .....### */
+ /*0175:*/ 0x06, /* .....##. */
+ /*0176:*/ 0x06, /* .....##. */
+ /*0177:*/ 0x0e, /* ....###. */
+ /*0178:*/ 0x0c, /* ....##.. */
+ /*0179:*/ 0x0c, /* ....##.. */
+ /*017a:*/ 0x1c, /* ...###.. */
+ /*017b:*/ 0x1c, /* ...###.. */
+ /*017c:*/ 0x18, /* ...##... */
+ /*017d:*/ 0x18, /* ...##... */
+ /*017e:*/ 0x38, /* ..###... */
+ /*017f:*/ 0x30, /* ..##.... */
+ /*0180:*/ 0x30, /* ..##.... */
+ /*0181:*/ 0x70, /* .###.... */
+ /*0182:*/ 0x60, /* .##..... */
+ /*0183:*/ 0x60, /* .##..... */
+ /*0184:*/ 0xe0, /* ###..... */
+ /*0185:*/ 0xe0, /* ###..... */
+/* --- new character zero (48) starting at offset 0x0186 --- */
+ /*0186:*/ 13, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*018b:*/ 0x1f,0x80, /* ...######....... */
+ /*018d:*/ 0x3f,0xc0, /* ..########...... */
+ /*018f:*/ 0x79,0xe0, /* .####..####..... */
+ /*0191:*/ 0x70,0xe0, /* .###....###..... */
+ /*0193:*/ 0x70,0xe0, /* .###....###..... */
+ /*0195:*/ 0xe0,0x70, /* ###......###.... */
+ /*0197:*/ 0xe0,0x70, /* ###......###.... */
+ /*0199:*/ 0xe0,0x70, /* ###......###.... */
+ /*019b:*/ 0xe0,0x70, /* ###......###.... */
+ /*019d:*/ 0xe0,0x70, /* ###......###.... */
+ /*019f:*/ 0xe0,0x70, /* ###......###.... */
+ /*01a1:*/ 0xe0,0x70, /* ###......###.... */
+ /*01a3:*/ 0xe0,0x70, /* ###......###.... */
+ /*01a5:*/ 0x70,0xe0, /* .###....###..... */
+ /*01a7:*/ 0x70,0xe0, /* .###....###..... */
+ /*01a9:*/ 0x79,0xe0, /* .####..####..... */
+ /*01ab:*/ 0x3f,0xc0, /* ..########...... */
+ /*01ad:*/ 0x1f,0x80, /* ...######....... */
+/* --- new character one (49) starting at offset 0x01af --- */
+ /*01af:*/ 13, 7, 18, 2, 0, /* width and bbox (w,h,x,y) */
+ /*01b4:*/ 0x0e, /* ....###. */
+ /*01b5:*/ 0x0e, /* ....###. */
+ /*01b6:*/ 0x1e, /* ...####. */
+ /*01b7:*/ 0xfe, /* #######. */
+ /*01b8:*/ 0xfe, /* #######. */
+ /*01b9:*/ 0x0e, /* ....###. */
+ /*01ba:*/ 0x0e, /* ....###. */
+ /*01bb:*/ 0x0e, /* ....###. */
+ /*01bc:*/ 0x0e, /* ....###. */
+ /*01bd:*/ 0x0e, /* ....###. */
+ /*01be:*/ 0x0e, /* ....###. */
+ /*01bf:*/ 0x0e, /* ....###. */
+ /*01c0:*/ 0x0e, /* ....###. */
+ /*01c1:*/ 0x0e, /* ....###. */
+ /*01c2:*/ 0x0e, /* ....###. */
+ /*01c3:*/ 0x0e, /* ....###. */
+ /*01c4:*/ 0x0e, /* ....###. */
+ /*01c5:*/ 0x0e, /* ....###. */
+/* --- new character two (50) starting at offset 0x01c6 --- */
+ /*01c6:*/ 13, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01cb:*/ 0x1f,0x00, /* ...#####........ */
+ /*01cd:*/ 0x7f,0xc0, /* .#########...... */
+ /*01cf:*/ 0x71,0xe0, /* .###...####..... */
+ /*01d1:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*01d3:*/ 0xe0,0x70, /* ###......###.... */
+ /*01d5:*/ 0xe0,0x70, /* ###......###.... */
+ /*01d7:*/ 0x00,0x70, /* .........###.... */
+ /*01d9:*/ 0x00,0xe0, /* ........###..... */
+ /*01db:*/ 0x01,0xe0, /* .......####..... */
+ /*01dd:*/ 0x03,0xc0, /* ......####...... */
+ /*01df:*/ 0x07,0x80, /* .....####....... */
+ /*01e1:*/ 0x1f,0x00, /* ...#####........ */
+ /*01e3:*/ 0x3c,0x00, /* ..####.......... */
+ /*01e5:*/ 0x78,0x00, /* .####........... */
+ /*01e7:*/ 0xf0,0x00, /* ####............ */
+ /*01e9:*/ 0xe0,0x00, /* ###............. */
+ /*01eb:*/ 0xff,0xf0, /* ############.... */
+ /*01ed:*/ 0xff,0xf0, /* ############.... */
+/* --- new character three (51) starting at offset 0x01ef --- */
+ /*01ef:*/ 13, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*01f4:*/ 0x1f,0x00, /* ...#####........ */
+ /*01f6:*/ 0x7f,0xc0, /* .#########...... */
+ /*01f8:*/ 0x71,0xc0, /* .###...###...... */
+ /*01fa:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*01fc:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*01fe:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0200:*/ 0x00,0xe0, /* ........###..... */
+ /*0202:*/ 0x01,0xc0, /* .......###...... */
+ /*0204:*/ 0x0f,0x80, /* ....#####....... */
+ /*0206:*/ 0x0f,0xe0, /* ....#######..... */
+ /*0208:*/ 0x00,0xe0, /* ........###..... */
+ /*020a:*/ 0x00,0x70, /* .........###.... */
+ /*020c:*/ 0x00,0x70, /* .........###.... */
+ /*020e:*/ 0xe0,0x70, /* ###......###.... */
+ /*0210:*/ 0xe0,0xf0, /* ###.....####.... */
+ /*0212:*/ 0x71,0xe0, /* .###...####..... */
+ /*0214:*/ 0x7f,0xe0, /* .##########..... */
+ /*0216:*/ 0x1f,0x80, /* ...######....... */
+/* --- new character four (52) starting at offset 0x0218 --- */
+ /*0218:*/ 13, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*021d:*/ 0x01,0xc0, /* .......###...... */
+ /*021f:*/ 0x03,0xc0, /* ......####...... */
+ /*0221:*/ 0x03,0xc0, /* ......####...... */
+ /*0223:*/ 0x07,0xc0, /* .....#####...... */
+ /*0225:*/ 0x07,0xc0, /* .....#####...... */
+ /*0227:*/ 0x0d,0xc0, /* ....##.###...... */
+ /*0229:*/ 0x1d,0xc0, /* ...###.###...... */
+ /*022b:*/ 0x19,0xc0, /* ...##..###...... */
+ /*022d:*/ 0x31,0xc0, /* ..##...###...... */
+ /*022f:*/ 0x71,0xc0, /* .###...###...... */
+ /*0231:*/ 0x61,0xc0, /* .##....###...... */
+ /*0233:*/ 0xe1,0xc0, /* ###....###...... */
+ /*0235:*/ 0xff,0xf0, /* ############.... */
+ /*0237:*/ 0xff,0xf0, /* ############.... */
+ /*0239:*/ 0x01,0xc0, /* .......###...... */
+ /*023b:*/ 0x01,0xc0, /* .......###...... */
+ /*023d:*/ 0x01,0xc0, /* .......###...... */
+ /*023f:*/ 0x01,0xc0, /* .......###...... */
+/* --- new character five (53) starting at offset 0x0241 --- */
+ /*0241:*/ 13, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0246:*/ 0x7f,0xe0, /* .##########..... */
+ /*0248:*/ 0x7f,0xe0, /* .##########..... */
+ /*024a:*/ 0x70,0x00, /* .###............ */
+ /*024c:*/ 0x70,0x00, /* .###............ */
+ /*024e:*/ 0x70,0x00, /* .###............ */
+ /*0250:*/ 0x70,0x00, /* .###............ */
+ /*0252:*/ 0x7f,0x80, /* .########....... */
+ /*0254:*/ 0x7f,0xc0, /* .#########...... */
+ /*0256:*/ 0x71,0xe0, /* .###...####..... */
+ /*0258:*/ 0x00,0xe0, /* ........###..... */
+ /*025a:*/ 0x00,0x70, /* .........###.... */
+ /*025c:*/ 0x00,0x70, /* .........###.... */
+ /*025e:*/ 0x00,0x70, /* .........###.... */
+ /*0260:*/ 0xe0,0x70, /* ###......###.... */
+ /*0262:*/ 0xe0,0xf0, /* ###.....####.... */
+ /*0264:*/ 0xf1,0xe0, /* ####...####..... */
+ /*0266:*/ 0x7f,0xc0, /* .#########...... */
+ /*0268:*/ 0x1f,0x80, /* ...######....... */
+/* --- new character six (54) starting at offset 0x026a --- */
+ /*026a:*/ 13, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*026f:*/ 0x0f,0x80, /* ....#####....... */
+ /*0271:*/ 0x3f,0xe0, /* ..#########..... */
+ /*0273:*/ 0x78,0xe0, /* .####...###..... */
+ /*0275:*/ 0x70,0x70, /* .###.....###.... */
+ /*0277:*/ 0xe0,0x70, /* ###......###.... */
+ /*0279:*/ 0xe0,0x00, /* ###............. */
+ /*027b:*/ 0xe0,0x00, /* ###............. */
+ /*027d:*/ 0xef,0x00, /* ###.####........ */
+ /*027f:*/ 0xff,0xc0, /* ##########...... */
+ /*0281:*/ 0xf9,0xe0, /* #####..####..... */
+ /*0283:*/ 0xf0,0xe0, /* ####....###..... */
+ /*0285:*/ 0xe0,0x70, /* ###......###.... */
+ /*0287:*/ 0xe0,0x70, /* ###......###.... */
+ /*0289:*/ 0xe0,0x70, /* ###......###.... */
+ /*028b:*/ 0x70,0xe0, /* .###....###..... */
+ /*028d:*/ 0x79,0xe0, /* .####..####..... */
+ /*028f:*/ 0x3f,0xc0, /* ..########...... */
+ /*0291:*/ 0x1f,0x80, /* ...######....... */
+/* --- new character seven (55) starting at offset 0x0293 --- */
+ /*0293:*/ 13, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0298:*/ 0xff,0xf0, /* ############.... */
+ /*029a:*/ 0xff,0xf0, /* ############.... */
+ /*029c:*/ 0x00,0xf0, /* ........####.... */
+ /*029e:*/ 0x00,0xe0, /* ........###..... */
+ /*02a0:*/ 0x01,0xc0, /* .......###...... */
+ /*02a2:*/ 0x01,0xc0, /* .......###...... */
+ /*02a4:*/ 0x03,0x80, /* ......###....... */
+ /*02a6:*/ 0x03,0x80, /* ......###....... */
+ /*02a8:*/ 0x07,0x00, /* .....###........ */
+ /*02aa:*/ 0x07,0x00, /* .....###........ */
+ /*02ac:*/ 0x0e,0x00, /* ....###......... */
+ /*02ae:*/ 0x0e,0x00, /* ....###......... */
+ /*02b0:*/ 0x1e,0x00, /* ...####......... */
+ /*02b2:*/ 0x1c,0x00, /* ...###.......... */
+ /*02b4:*/ 0x1c,0x00, /* ...###.......... */
+ /*02b6:*/ 0x3c,0x00, /* ..####.......... */
+ /*02b8:*/ 0x38,0x00, /* ..###........... */
+ /*02ba:*/ 0x38,0x00, /* ..###........... */
+/* --- new character eight (56) starting at offset 0x02bc --- */
+ /*02bc:*/ 13, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02c1:*/ 0x0f,0x00, /* ....####........ */
+ /*02c3:*/ 0x3f,0xc0, /* ..########...... */
+ /*02c5:*/ 0x39,0xc0, /* ..###..###...... */
+ /*02c7:*/ 0x70,0xe0, /* .###....###..... */
+ /*02c9:*/ 0x70,0xe0, /* .###....###..... */
+ /*02cb:*/ 0x70,0xe0, /* .###....###..... */
+ /*02cd:*/ 0x70,0xe0, /* .###....###..... */
+ /*02cf:*/ 0x39,0xc0, /* ..###..###...... */
+ /*02d1:*/ 0x1f,0x80, /* ...######....... */
+ /*02d3:*/ 0x3f,0xc0, /* ..########...... */
+ /*02d5:*/ 0x70,0xe0, /* .###....###..... */
+ /*02d7:*/ 0xe0,0x70, /* ###......###.... */
+ /*02d9:*/ 0xe0,0x70, /* ###......###.... */
+ /*02db:*/ 0xe0,0x70, /* ###......###.... */
+ /*02dd:*/ 0xe0,0x70, /* ###......###.... */
+ /*02df:*/ 0x70,0xe0, /* .###....###..... */
+ /*02e1:*/ 0x7f,0xe0, /* .##########..... */
+ /*02e3:*/ 0x1f,0x80, /* ...######....... */
+/* --- new character nine (57) starting at offset 0x02e5 --- */
+ /*02e5:*/ 13, 12, 18, 0, 0, /* width and bbox (w,h,x,y) */
+ /*02ea:*/ 0x1f,0x80, /* ...######....... */
+ /*02ec:*/ 0x7f,0xc0, /* .#########...... */
+ /*02ee:*/ 0x79,0xe0, /* .####..####..... */
+ /*02f0:*/ 0xf0,0xe0, /* ####....###..... */
+ /*02f2:*/ 0xe0,0x70, /* ###......###.... */
+ /*02f4:*/ 0xe0,0x70, /* ###......###.... */
+ /*02f6:*/ 0xe0,0x70, /* ###......###.... */
+ /*02f8:*/ 0xe0,0x70, /* ###......###.... */
+ /*02fa:*/ 0xf0,0xf0, /* ####....####.... */
+ /*02fc:*/ 0x79,0xf0, /* .####..#####.... */
+ /*02fe:*/ 0x7f,0xf0, /* .###########.... */
+ /*0300:*/ 0x1f,0x70, /* ...#####.###.... */
+ /*0302:*/ 0x00,0x70, /* .........###.... */
+ /*0304:*/ 0x00,0x70, /* .........###.... */
+ /*0306:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0308:*/ 0xf3,0xe0, /* ####..#####..... */
+ /*030a:*/ 0x7f,0xc0, /* .#########...... */
+ /*030c:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character colon (58) starting at offset 0x030e --- */
+ /*030e:*/ 7, 3, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0313:*/ 0xe0, /* ###..... */
+ /*0314:*/ 0xe0, /* ###..... */
+ /*0315:*/ 0xe0, /* ###..... */
+ /*0316:*/ 0x00, /* ........ */
+ /*0317:*/ 0x00, /* ........ */
+ /*0318:*/ 0x00, /* ........ */
+ /*0319:*/ 0x00, /* ........ */
+ /*031a:*/ 0x00, /* ........ */
+ /*031b:*/ 0x00, /* ........ */
+ /*031c:*/ 0x00, /* ........ */
+ /*031d:*/ 0x00, /* ........ */
+ /*031e:*/ 0xe0, /* ###..... */
+ /*031f:*/ 0xe0, /* ###..... */
+ /*0320:*/ 0xe0, /* ###..... */
+/* --- new character semicolon (59) starting at offset 0x0321 --- */
+ /*0321:*/ 7, 3, 17, 2, -3, /* width and bbox (w,h,x,y) */
+ /*0326:*/ 0xe0, /* ###..... */
+ /*0327:*/ 0xe0, /* ###..... */
+ /*0328:*/ 0xe0, /* ###..... */
+ /*0329:*/ 0x00, /* ........ */
+ /*032a:*/ 0x00, /* ........ */
+ /*032b:*/ 0x00, /* ........ */
+ /*032c:*/ 0x00, /* ........ */
+ /*032d:*/ 0x00, /* ........ */
+ /*032e:*/ 0x00, /* ........ */
+ /*032f:*/ 0x00, /* ........ */
+ /*0330:*/ 0x00, /* ........ */
+ /*0331:*/ 0xe0, /* ###..... */
+ /*0332:*/ 0xe0, /* ###..... */
+ /*0333:*/ 0xe0, /* ###..... */
+ /*0334:*/ 0x60, /* .##..... */
+ /*0335:*/ 0x60, /* .##..... */
+ /*0336:*/ 0xc0, /* ##...... */
+/* --- new character less (60) starting at offset 0x0337 --- */
+ /*0337:*/ 15, 13, 12, 0, 1, /* width and bbox (w,h,x,y) */
+ /*033c:*/ 0x00,0x38, /* ..........###... */
+ /*033e:*/ 0x00,0xf8, /* ........#####... */
+ /*0340:*/ 0x03,0xe0, /* ......#####..... */
+ /*0342:*/ 0x0f,0x80, /* ....#####....... */
+ /*0344:*/ 0x3e,0x00, /* ..#####......... */
+ /*0346:*/ 0xf0,0x00, /* ####............ */
+ /*0348:*/ 0xf0,0x00, /* ####............ */
+ /*034a:*/ 0x3e,0x00, /* ..#####......... */
+ /*034c:*/ 0x0f,0x80, /* ....#####....... */
+ /*034e:*/ 0x03,0xe0, /* ......#####..... */
+ /*0350:*/ 0x00,0xf8, /* ........#####... */
+ /*0352:*/ 0x00,0x38, /* ..........###... */
+/* --- new character equal (61) starting at offset 0x0354 --- */
+ /*0354:*/ 14, 10, 6, 2, 4, /* width and bbox (w,h,x,y) */
+ /*0359:*/ 0xff,0xc0, /* ##########...... */
+ /*035b:*/ 0xff,0xc0, /* ##########...... */
+ /*035d:*/ 0x00,0x00, /* ................ */
+ /*035f:*/ 0x00,0x00, /* ................ */
+ /*0361:*/ 0xff,0xc0, /* ##########...... */
+ /*0363:*/ 0xff,0xc0, /* ##########...... */
+/* --- new character greater (62) starting at offset 0x0365 --- */
+ /*0365:*/ 14, 13, 12, 0, 1, /* width and bbox (w,h,x,y) */
+ /*036a:*/ 0xe0,0x00, /* ###............. */
+ /*036c:*/ 0xf8,0x00, /* #####........... */
+ /*036e:*/ 0x3e,0x00, /* ..#####......... */
+ /*0370:*/ 0x0f,0x80, /* ....#####....... */
+ /*0372:*/ 0x03,0xe0, /* ......#####..... */
+ /*0374:*/ 0x00,0x78, /* .........####... */
+ /*0376:*/ 0x00,0x78, /* .........####... */
+ /*0378:*/ 0x03,0xe0, /* ......#####..... */
+ /*037a:*/ 0x0f,0x80, /* ....#####....... */
+ /*037c:*/ 0x3e,0x00, /* ..#####......... */
+ /*037e:*/ 0xf8,0x00, /* #####........... */
+ /*0380:*/ 0xe0,0x00, /* ###............. */
+/* --- new character question (63) starting at offset 0x0382 --- */
+ /*0382:*/ 15, 11, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0387:*/ 0x1f,0x80, /* ...######....... */
+ /*0389:*/ 0x7f,0xc0, /* .#########...... */
+ /*038b:*/ 0x79,0xe0, /* .####..####..... */
+ /*038d:*/ 0xf0,0xe0, /* ####....###..... */
+ /*038f:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0391:*/ 0xe1,0xe0, /* ###....####..... */
+ /*0393:*/ 0x01,0xc0, /* .......###...... */
+ /*0395:*/ 0x03,0xc0, /* ......####...... */
+ /*0397:*/ 0x07,0x80, /* .....####....... */
+ /*0399:*/ 0x07,0x00, /* .....###........ */
+ /*039b:*/ 0x0e,0x00, /* ....###......... */
+ /*039d:*/ 0x0e,0x00, /* ....###......... */
+ /*039f:*/ 0x0e,0x00, /* ....###......... */
+ /*03a1:*/ 0x0e,0x00, /* ....###......... */
+ /*03a3:*/ 0x00,0x00, /* ................ */
+ /*03a5:*/ 0x00,0x00, /* ................ */
+ /*03a7:*/ 0x0e,0x00, /* ....###......... */
+ /*03a9:*/ 0x0e,0x00, /* ....###......... */
+ /*03ab:*/ 0x0e,0x00, /* ....###......... */
+/* --- new character at (64) starting at offset 0x03ad --- */
+ /*03ad:*/ 24, 22, 22, 1, -4, /* width and bbox (w,h,x,y) */
+ /*03b2:*/ 0x01,0xff,0x00, /* .......#########........ */
+ /*03b5:*/ 0x07,0xff,0xc0, /* .....#############...... */
+ /*03b8:*/ 0x0f,0x81,0xf0, /* ....#####......#####.... */
+ /*03bb:*/ 0x1e,0x00,0x78, /* ...####..........####... */
+ /*03be:*/ 0x3c,0x00,0x38, /* ..####............###... */
+ /*03c1:*/ 0x78,0x7d,0x9c, /* .####....#####.##..###.. */
+ /*03c4:*/ 0x70,0xff,0x9c, /* .###....#########..###.. */
+ /*03c7:*/ 0xf1,0xc7,0x1c, /* ####...###...###...###.. */
+ /*03ca:*/ 0xe3,0x87,0x1c, /* ###...###....###...###.. */
+ /*03cd:*/ 0xe3,0x0e,0x1c, /* ###...##....###....###.. */
+ /*03d0:*/ 0xe7,0x0e,0x38, /* ###..###....###...###... */
+ /*03d3:*/ 0xe7,0x0c,0x38, /* ###..###....##....###... */
+ /*03d6:*/ 0xe7,0x1c,0x70, /* ###..###...###...###.... */
+ /*03d9:*/ 0xe7,0x1c,0x70, /* ###..###...###...###.... */
+ /*03dc:*/ 0xe3,0x9d,0xe0, /* ###...###..###.####..... */
+ /*03df:*/ 0xf3,0xff,0xc0, /* ####..############...... */
+ /*03e2:*/ 0x71,0xf7,0x00, /* .###...#####.###........ */
+ /*03e5:*/ 0x78,0x00,0x00, /* .####................... */
+ /*03e8:*/ 0x3c,0x00,0x00, /* ..####.................. */
+ /*03eb:*/ 0x1f,0x07,0x00, /* ...#####.....###........ */
+ /*03ee:*/ 0x0f,0xff,0x00, /* ....############........ */
+ /*03f1:*/ 0x03,0xfc,0x00, /* ......########.......... */
+/* --- new character A (65) starting at offset 0x03f4 --- */
+ /*03f4:*/ 18, 16, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*03f9:*/ 0x03,0xc0, /* ......####...... */
+ /*03fb:*/ 0x03,0xc0, /* ......####...... */
+ /*03fd:*/ 0x07,0xe0, /* .....######..... */
+ /*03ff:*/ 0x07,0xe0, /* .....######..... */
+ /*0401:*/ 0x0e,0x60, /* ....###..##..... */
+ /*0403:*/ 0x0e,0x70, /* ....###..###.... */
+ /*0405:*/ 0x0e,0x70, /* ....###..###.... */
+ /*0407:*/ 0x1c,0x38, /* ...###....###... */
+ /*0409:*/ 0x1c,0x38, /* ...###....###... */
+ /*040b:*/ 0x1c,0x38, /* ...###....###... */
+ /*040d:*/ 0x38,0x1c, /* ..###......###.. */
+ /*040f:*/ 0x38,0x1c, /* ..###......###.. */
+ /*0411:*/ 0x3f,0xfc, /* ..############.. */
+ /*0413:*/ 0x7f,0xfe, /* .##############. */
+ /*0415:*/ 0x70,0x0e, /* .###........###. */
+ /*0417:*/ 0x70,0x0e, /* .###........###. */
+ /*0419:*/ 0xe0,0x07, /* ###..........### */
+ /*041b:*/ 0xe0,0x07, /* ###..........### */
+ /*041d:*/ 0xe0,0x07, /* ###..........### */
+/* --- new character B (66) starting at offset 0x041f --- */
+ /*041f:*/ 18, 15, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0424:*/ 0xff,0xe0, /* ###########..... */
+ /*0426:*/ 0xff,0xf8, /* #############... */
+ /*0428:*/ 0xe0,0x78, /* ###......####... */
+ /*042a:*/ 0xe0,0x1c, /* ###........###.. */
+ /*042c:*/ 0xe0,0x1c, /* ###........###.. */
+ /*042e:*/ 0xe0,0x1c, /* ###........###.. */
+ /*0430:*/ 0xe0,0x1c, /* ###........###.. */
+ /*0432:*/ 0xe0,0x38, /* ###.......###... */
+ /*0434:*/ 0xff,0xf0, /* ############.... */
+ /*0436:*/ 0xff,0xf8, /* #############... */
+ /*0438:*/ 0xe0,0x1c, /* ###........###.. */
+ /*043a:*/ 0xe0,0x0e, /* ###.........###. */
+ /*043c:*/ 0xe0,0x0e, /* ###.........###. */
+ /*043e:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0440:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0442:*/ 0xe0,0x1e, /* ###........####. */
+ /*0444:*/ 0xe0,0x7c, /* ###......#####.. */
+ /*0446:*/ 0xff,0xf8, /* #############... */
+ /*0448:*/ 0xff,0xe0, /* ###########..... */
+/* --- new character C (67) starting at offset 0x044a --- */
+ /*044a:*/ 18, 16, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*044f:*/ 0x07,0xf0, /* .....#######.... */
+ /*0451:*/ 0x1f,0xfc, /* ...###########.. */
+ /*0453:*/ 0x3e,0x3e, /* ..#####...#####. */
+ /*0455:*/ 0x78,0x0f, /* .####.......#### */
+ /*0457:*/ 0x70,0x07, /* .###.........### */
+ /*0459:*/ 0xf0,0x00, /* ####............ */
+ /*045b:*/ 0xe0,0x00, /* ###............. */
+ /*045d:*/ 0xe0,0x00, /* ###............. */
+ /*045f:*/ 0xe0,0x00, /* ###............. */
+ /*0461:*/ 0xe0,0x00, /* ###............. */
+ /*0463:*/ 0xe0,0x00, /* ###............. */
+ /*0465:*/ 0xe0,0x00, /* ###............. */
+ /*0467:*/ 0xe0,0x00, /* ###............. */
+ /*0469:*/ 0xf0,0x07, /* ####.........### */
+ /*046b:*/ 0x70,0x07, /* .###.........### */
+ /*046d:*/ 0x78,0x0f, /* .####.......#### */
+ /*046f:*/ 0x3e,0x3e, /* ..#####...#####. */
+ /*0471:*/ 0x1f,0xfc, /* ...###########.. */
+ /*0473:*/ 0x07,0xf0, /* .....#######.... */
+/* --- new character D (68) starting at offset 0x0475 --- */
+ /*0475:*/ 19, 16, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*047a:*/ 0xff,0xe0, /* ###########..... */
+ /*047c:*/ 0xff,0xf8, /* #############... */
+ /*047e:*/ 0xe0,0x7c, /* ###......#####.. */
+ /*0480:*/ 0xe0,0x1e, /* ###........####. */
+ /*0482:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0484:*/ 0xe0,0x0f, /* ###.........#### */
+ /*0486:*/ 0xe0,0x07, /* ###..........### */
+ /*0488:*/ 0xe0,0x07, /* ###..........### */
+ /*048a:*/ 0xe0,0x07, /* ###..........### */
+ /*048c:*/ 0xe0,0x07, /* ###..........### */
+ /*048e:*/ 0xe0,0x07, /* ###..........### */
+ /*0490:*/ 0xe0,0x07, /* ###..........### */
+ /*0492:*/ 0xe0,0x07, /* ###..........### */
+ /*0494:*/ 0xe0,0x0f, /* ###.........#### */
+ /*0496:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0498:*/ 0xe0,0x1e, /* ###........####. */
+ /*049a:*/ 0xe0,0x7c, /* ###......#####.. */
+ /*049c:*/ 0xff,0xf8, /* #############... */
+ /*049e:*/ 0xff,0xe0, /* ###########..... */
+/* --- new character E (69) starting at offset 0x04a0 --- */
+ /*04a0:*/ 16, 13, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*04a5:*/ 0xff,0xf0, /* ############.... */
+ /*04a7:*/ 0xff,0xf0, /* ############.... */
+ /*04a9:*/ 0xe0,0x00, /* ###............. */
+ /*04ab:*/ 0xe0,0x00, /* ###............. */
+ /*04ad:*/ 0xe0,0x00, /* ###............. */
+ /*04af:*/ 0xe0,0x00, /* ###............. */
+ /*04b1:*/ 0xe0,0x00, /* ###............. */
+ /*04b3:*/ 0xe0,0x00, /* ###............. */
+ /*04b5:*/ 0xff,0xe0, /* ###########..... */
+ /*04b7:*/ 0xff,0xe0, /* ###########..... */
+ /*04b9:*/ 0xe0,0x00, /* ###............. */
+ /*04bb:*/ 0xe0,0x00, /* ###............. */
+ /*04bd:*/ 0xe0,0x00, /* ###............. */
+ /*04bf:*/ 0xe0,0x00, /* ###............. */
+ /*04c1:*/ 0xe0,0x00, /* ###............. */
+ /*04c3:*/ 0xe0,0x00, /* ###............. */
+ /*04c5:*/ 0xe0,0x00, /* ###............. */
+ /*04c7:*/ 0xff,0xf8, /* #############... */
+ /*04c9:*/ 0xff,0xf8, /* #############... */
+/* --- new character F (70) starting at offset 0x04cb --- */
+ /*04cb:*/ 15, 12, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*04d0:*/ 0xff,0xf0, /* ############.... */
+ /*04d2:*/ 0xff,0xf0, /* ############.... */
+ /*04d4:*/ 0xe0,0x00, /* ###............. */
+ /*04d6:*/ 0xe0,0x00, /* ###............. */
+ /*04d8:*/ 0xe0,0x00, /* ###............. */
+ /*04da:*/ 0xe0,0x00, /* ###............. */
+ /*04dc:*/ 0xe0,0x00, /* ###............. */
+ /*04de:*/ 0xe0,0x00, /* ###............. */
+ /*04e0:*/ 0xff,0xe0, /* ###########..... */
+ /*04e2:*/ 0xff,0xe0, /* ###########..... */
+ /*04e4:*/ 0xe0,0x00, /* ###............. */
+ /*04e6:*/ 0xe0,0x00, /* ###............. */
+ /*04e8:*/ 0xe0,0x00, /* ###............. */
+ /*04ea:*/ 0xe0,0x00, /* ###............. */
+ /*04ec:*/ 0xe0,0x00, /* ###............. */
+ /*04ee:*/ 0xe0,0x00, /* ###............. */
+ /*04f0:*/ 0xe0,0x00, /* ###............. */
+ /*04f2:*/ 0xe0,0x00, /* ###............. */
+ /*04f4:*/ 0xe0,0x00, /* ###............. */
+/* --- new character G (71) starting at offset 0x04f6 --- */
+ /*04f6:*/ 19, 17, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04fb:*/ 0x07,0xf0,0x00, /* .....#######............ */
+ /*04fe:*/ 0x1f,0xfc,0x00, /* ...###########.......... */
+ /*0501:*/ 0x3e,0x3e,0x00, /* ..#####...#####......... */
+ /*0504:*/ 0x78,0x0f,0x00, /* .####.......####........ */
+ /*0507:*/ 0x70,0x07,0x00, /* .###.........###........ */
+ /*050a:*/ 0xf0,0x00,0x00, /* ####.................... */
+ /*050d:*/ 0xe0,0x00,0x00, /* ###..................... */
+ /*0510:*/ 0xe0,0x00,0x00, /* ###..................... */
+ /*0513:*/ 0xe0,0x00,0x00, /* ###..................... */
+ /*0516:*/ 0xe0,0x7f,0x80, /* ###......########....... */
+ /*0519:*/ 0xe0,0x7f,0x80, /* ###......########....... */
+ /*051c:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*051f:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*0522:*/ 0xf0,0x03,0x80, /* ####..........###....... */
+ /*0525:*/ 0x70,0x07,0x80, /* .###.........####....... */
+ /*0528:*/ 0x78,0x0f,0x80, /* .####.......#####....... */
+ /*052b:*/ 0x3e,0x3f,0x80, /* ..#####...#######....... */
+ /*052e:*/ 0x1f,0xfb,0x80, /* ...##########.###....... */
+ /*0531:*/ 0x07,0xf1,0x80, /* .....#######...##....... */
+/* --- new character H (72) starting at offset 0x0534 --- */
+ /*0534:*/ 19, 15, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0539:*/ 0xe0,0x0e, /* ###.........###. */
+ /*053b:*/ 0xe0,0x0e, /* ###.........###. */
+ /*053d:*/ 0xe0,0x0e, /* ###.........###. */
+ /*053f:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0541:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0543:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0545:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0547:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0549:*/ 0xff,0xfe, /* ###############. */
+ /*054b:*/ 0xff,0xfe, /* ###############. */
+ /*054d:*/ 0xe0,0x0e, /* ###.........###. */
+ /*054f:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0551:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0553:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0555:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0557:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0559:*/ 0xe0,0x0e, /* ###.........###. */
+ /*055b:*/ 0xe0,0x0e, /* ###.........###. */
+ /*055d:*/ 0xe0,0x0e, /* ###.........###. */
+/* --- new character I (73) starting at offset 0x055f --- */
+ /*055f:*/ 7, 3, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0564:*/ 0xe0, /* ###..... */
+ /*0565:*/ 0xe0, /* ###..... */
+ /*0566:*/ 0xe0, /* ###..... */
+ /*0567:*/ 0xe0, /* ###..... */
+ /*0568:*/ 0xe0, /* ###..... */
+ /*0569:*/ 0xe0, /* ###..... */
+ /*056a:*/ 0xe0, /* ###..... */
+ /*056b:*/ 0xe0, /* ###..... */
+ /*056c:*/ 0xe0, /* ###..... */
+ /*056d:*/ 0xe0, /* ###..... */
+ /*056e:*/ 0xe0, /* ###..... */
+ /*056f:*/ 0xe0, /* ###..... */
+ /*0570:*/ 0xe0, /* ###..... */
+ /*0571:*/ 0xe0, /* ###..... */
+ /*0572:*/ 0xe0, /* ###..... */
+ /*0573:*/ 0xe0, /* ###..... */
+ /*0574:*/ 0xe0, /* ###..... */
+ /*0575:*/ 0xe0, /* ###..... */
+ /*0576:*/ 0xe0, /* ###..... */
+/* --- new character J (74) starting at offset 0x0577 --- */
+ /*0577:*/ 14, 11, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*057c:*/ 0x00,0xe0, /* ........###..... */
+ /*057e:*/ 0x00,0xe0, /* ........###..... */
+ /*0580:*/ 0x00,0xe0, /* ........###..... */
+ /*0582:*/ 0x00,0xe0, /* ........###..... */
+ /*0584:*/ 0x00,0xe0, /* ........###..... */
+ /*0586:*/ 0x00,0xe0, /* ........###..... */
+ /*0588:*/ 0x00,0xe0, /* ........###..... */
+ /*058a:*/ 0x00,0xe0, /* ........###..... */
+ /*058c:*/ 0x00,0xe0, /* ........###..... */
+ /*058e:*/ 0x00,0xe0, /* ........###..... */
+ /*0590:*/ 0x00,0xe0, /* ........###..... */
+ /*0592:*/ 0x00,0xe0, /* ........###..... */
+ /*0594:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0596:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0598:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*059a:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*059c:*/ 0x71,0xe0, /* .###...####..... */
+ /*059e:*/ 0x7f,0xc0, /* .#########...... */
+ /*05a0:*/ 0x3f,0x80, /* ..#######....... */
+/* --- new character K (75) starting at offset 0x05a2 --- */
+ /*05a2:*/ 18, 16, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*05a7:*/ 0xe0,0x3c, /* ###.......####.. */
+ /*05a9:*/ 0xe0,0x78, /* ###......####... */
+ /*05ab:*/ 0xe0,0xf0, /* ###.....####.... */
+ /*05ad:*/ 0xe1,0xe0, /* ###....####..... */
+ /*05af:*/ 0xe3,0xc0, /* ###...####...... */
+ /*05b1:*/ 0xe7,0x80, /* ###..####....... */
+ /*05b3:*/ 0xef,0x00, /* ###.####........ */
+ /*05b5:*/ 0xfe,0x00, /* #######......... */
+ /*05b7:*/ 0xfe,0x00, /* #######......... */
+ /*05b9:*/ 0xff,0x00, /* ########........ */
+ /*05bb:*/ 0xf7,0x80, /* ####.####....... */
+ /*05bd:*/ 0xe3,0xc0, /* ###...####...... */
+ /*05bf:*/ 0xe1,0xe0, /* ###....####..... */
+ /*05c1:*/ 0xe0,0xf0, /* ###.....####.... */
+ /*05c3:*/ 0xe0,0x78, /* ###......####... */
+ /*05c5:*/ 0xe0,0x3c, /* ###.......####.. */
+ /*05c7:*/ 0xe0,0x1e, /* ###........####. */
+ /*05c9:*/ 0xe0,0x0f, /* ###.........#### */
+ /*05cb:*/ 0xe0,0x07, /* ###..........### */
+/* --- new character L (76) starting at offset 0x05cd --- */
+ /*05cd:*/ 15, 12, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*05d2:*/ 0xe0,0x00, /* ###............. */
+ /*05d4:*/ 0xe0,0x00, /* ###............. */
+ /*05d6:*/ 0xe0,0x00, /* ###............. */
+ /*05d8:*/ 0xe0,0x00, /* ###............. */
+ /*05da:*/ 0xe0,0x00, /* ###............. */
+ /*05dc:*/ 0xe0,0x00, /* ###............. */
+ /*05de:*/ 0xe0,0x00, /* ###............. */
+ /*05e0:*/ 0xe0,0x00, /* ###............. */
+ /*05e2:*/ 0xe0,0x00, /* ###............. */
+ /*05e4:*/ 0xe0,0x00, /* ###............. */
+ /*05e6:*/ 0xe0,0x00, /* ###............. */
+ /*05e8:*/ 0xe0,0x00, /* ###............. */
+ /*05ea:*/ 0xe0,0x00, /* ###............. */
+ /*05ec:*/ 0xe0,0x00, /* ###............. */
+ /*05ee:*/ 0xe0,0x00, /* ###............. */
+ /*05f0:*/ 0xe0,0x00, /* ###............. */
+ /*05f2:*/ 0xe0,0x00, /* ###............. */
+ /*05f4:*/ 0xff,0xf0, /* ############.... */
+ /*05f6:*/ 0xff,0xf0, /* ############.... */
+/* --- new character M (77) starting at offset 0x05f8 --- */
+ /*05f8:*/ 23, 19, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*05fd:*/ 0xe0,0x00,0xe0, /* ###.............###..... */
+ /*0600:*/ 0xf0,0x01,0xe0, /* ####...........####..... */
+ /*0603:*/ 0xf0,0x01,0xe0, /* ####...........####..... */
+ /*0606:*/ 0xf8,0x03,0xe0, /* #####.........#####..... */
+ /*0609:*/ 0xf8,0x03,0xe0, /* #####.........#####..... */
+ /*060c:*/ 0xfc,0x07,0xe0, /* ######.......######..... */
+ /*060f:*/ 0xec,0x06,0xe0, /* ###.##.......##.###..... */
+ /*0612:*/ 0xee,0x0e,0xe0, /* ###.###.....###.###..... */
+ /*0615:*/ 0xe6,0x0c,0xe0, /* ###..##.....##..###..... */
+ /*0618:*/ 0xe7,0x1c,0xe0, /* ###..###...###..###..... */
+ /*061b:*/ 0xe7,0x1c,0xe0, /* ###..###...###..###..... */
+ /*061e:*/ 0xe3,0x18,0xe0, /* ###...##...##...###..... */
+ /*0621:*/ 0xe3,0xb8,0xe0, /* ###...###.###...###..... */
+ /*0624:*/ 0xe3,0xb8,0xe0, /* ###...###.###...###..... */
+ /*0627:*/ 0xe1,0xf0,0xe0, /* ###....#####....###..... */
+ /*062a:*/ 0xe1,0xf0,0xe0, /* ###....#####....###..... */
+ /*062d:*/ 0xe0,0xe0,0xe0, /* ###.....###.....###..... */
+ /*0630:*/ 0xe0,0xe0,0xe0, /* ###.....###.....###..... */
+ /*0633:*/ 0xe0,0xe0,0xe0, /* ###.....###.....###..... */
+/* --- new character N (78) starting at offset 0x0636 --- */
+ /*0636:*/ 19, 15, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*063b:*/ 0xe0,0x0e, /* ###.........###. */
+ /*063d:*/ 0xf0,0x0e, /* ####........###. */
+ /*063f:*/ 0xf0,0x0e, /* ####........###. */
+ /*0641:*/ 0xf8,0x0e, /* #####.......###. */
+ /*0643:*/ 0xf8,0x0e, /* #####.......###. */
+ /*0645:*/ 0xfc,0x0e, /* ######......###. */
+ /*0647:*/ 0xee,0x0e, /* ###.###.....###. */
+ /*0649:*/ 0xee,0x0e, /* ###.###.....###. */
+ /*064b:*/ 0xe7,0x0e, /* ###..###....###. */
+ /*064d:*/ 0xe3,0x8e, /* ###...###...###. */
+ /*064f:*/ 0xe3,0x8e, /* ###...###...###. */
+ /*0651:*/ 0xe1,0xce, /* ###....###..###. */
+ /*0653:*/ 0xe0,0xce, /* ###.....##..###. */
+ /*0655:*/ 0xe0,0xee, /* ###.....###.###. */
+ /*0657:*/ 0xe0,0x7e, /* ###......######. */
+ /*0659:*/ 0xe0,0x3e, /* ###.......#####. */
+ /*065b:*/ 0xe0,0x3e, /* ###.......#####. */
+ /*065d:*/ 0xe0,0x1e, /* ###........####. */
+ /*065f:*/ 0xe0,0x0e, /* ###.........###. */
+/* --- new character O (79) starting at offset 0x0661 --- */
+ /*0661:*/ 19, 17, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0666:*/ 0x07,0xf0,0x00, /* .....#######............ */
+ /*0669:*/ 0x1f,0xfc,0x00, /* ...###########.......... */
+ /*066c:*/ 0x3e,0x3e,0x00, /* ..#####...#####......... */
+ /*066f:*/ 0x78,0x0f,0x00, /* .####.......####........ */
+ /*0672:*/ 0x70,0x07,0x00, /* .###.........###........ */
+ /*0675:*/ 0xf0,0x07,0x80, /* ####.........####....... */
+ /*0678:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*067b:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*067e:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*0681:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*0684:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*0687:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*068a:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*068d:*/ 0xf0,0x07,0x80, /* ####.........####....... */
+ /*0690:*/ 0x70,0x07,0x00, /* .###.........###........ */
+ /*0693:*/ 0x78,0x0f,0x00, /* .####.......####........ */
+ /*0696:*/ 0x3e,0x3e,0x00, /* ..#####...#####......... */
+ /*0699:*/ 0x1f,0xfc,0x00, /* ...###########.......... */
+ /*069c:*/ 0x07,0xf0,0x00, /* .....#######............ */
+/* --- new character P (80) starting at offset 0x069f --- */
+ /*069f:*/ 17, 14, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*06a4:*/ 0xff,0xe0, /* ###########..... */
+ /*06a6:*/ 0xff,0xf8, /* #############... */
+ /*06a8:*/ 0xe0,0x38, /* ###.......###... */
+ /*06aa:*/ 0xe0,0x1c, /* ###........###.. */
+ /*06ac:*/ 0xe0,0x1c, /* ###........###.. */
+ /*06ae:*/ 0xe0,0x1c, /* ###........###.. */
+ /*06b0:*/ 0xe0,0x1c, /* ###........###.. */
+ /*06b2:*/ 0xe0,0x38, /* ###.......###... */
+ /*06b4:*/ 0xff,0xf8, /* #############... */
+ /*06b6:*/ 0xff,0xf0, /* ############.... */
+ /*06b8:*/ 0xe0,0x00, /* ###............. */
+ /*06ba:*/ 0xe0,0x00, /* ###............. */
+ /*06bc:*/ 0xe0,0x00, /* ###............. */
+ /*06be:*/ 0xe0,0x00, /* ###............. */
+ /*06c0:*/ 0xe0,0x00, /* ###............. */
+ /*06c2:*/ 0xe0,0x00, /* ###............. */
+ /*06c4:*/ 0xe0,0x00, /* ###............. */
+ /*06c6:*/ 0xe0,0x00, /* ###............. */
+ /*06c8:*/ 0xe0,0x00, /* ###............. */
+/* --- new character Q (81) starting at offset 0x06ca --- */
+ /*06ca:*/ 19, 17, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*06cf:*/ 0x07,0xf0,0x00, /* .....#######............ */
+ /*06d2:*/ 0x1f,0xfc,0x00, /* ...###########.......... */
+ /*06d5:*/ 0x3e,0x3e,0x00, /* ..#####...#####......... */
+ /*06d8:*/ 0x78,0x0f,0x00, /* .####.......####........ */
+ /*06db:*/ 0x70,0x07,0x00, /* .###.........###........ */
+ /*06de:*/ 0xf0,0x07,0x80, /* ####.........####....... */
+ /*06e1:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*06e4:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*06e7:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*06ea:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*06ed:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*06f0:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*06f3:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*06f6:*/ 0xf0,0x07,0x80, /* ####.........####....... */
+ /*06f9:*/ 0x70,0xf7,0x00, /* .###....####.###........ */
+ /*06fc:*/ 0x78,0x7f,0x00, /* .####....#######........ */
+ /*06ff:*/ 0x3e,0x1e,0x00, /* ..#####....####......... */
+ /*0702:*/ 0x1f,0xff,0x00, /* ...#############........ */
+ /*0705:*/ 0x07,0xf7,0x80, /* .....#######.####....... */
+/* --- new character R (82) starting at offset 0x0708 --- */
+ /*0708:*/ 17, 14, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*070d:*/ 0xff,0xe0, /* ###########..... */
+ /*070f:*/ 0xff,0xf8, /* #############... */
+ /*0711:*/ 0xe0,0x38, /* ###.......###... */
+ /*0713:*/ 0xe0,0x1c, /* ###........###.. */
+ /*0715:*/ 0xe0,0x1c, /* ###........###.. */
+ /*0717:*/ 0xe0,0x1c, /* ###........###.. */
+ /*0719:*/ 0xe0,0x1c, /* ###........###.. */
+ /*071b:*/ 0xe0,0x38, /* ###.......###... */
+ /*071d:*/ 0xff,0xf8, /* #############... */
+ /*071f:*/ 0xff,0xf0, /* ############.... */
+ /*0721:*/ 0xe0,0x78, /* ###......####... */
+ /*0723:*/ 0xe0,0x38, /* ###.......###... */
+ /*0725:*/ 0xe0,0x1c, /* ###........###.. */
+ /*0727:*/ 0xe0,0x1c, /* ###........###.. */
+ /*0729:*/ 0xe0,0x1c, /* ###........###.. */
+ /*072b:*/ 0xe0,0x1c, /* ###........###.. */
+ /*072d:*/ 0xe0,0x1c, /* ###........###.. */
+ /*072f:*/ 0xe0,0x1c, /* ###........###.. */
+ /*0731:*/ 0xe0,0x1c, /* ###........###.. */
+/* --- new character S (83) starting at offset 0x0733 --- */
+ /*0733:*/ 17, 15, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0738:*/ 0x07,0xe0, /* .....######..... */
+ /*073a:*/ 0x1f,0xf8, /* ...##########... */
+ /*073c:*/ 0x3c,0x7c, /* ..####...#####.. */
+ /*073e:*/ 0x78,0x1c, /* .####......###.. */
+ /*0740:*/ 0x70,0x1c, /* .###.......###.. */
+ /*0742:*/ 0x70,0x00, /* .###............ */
+ /*0744:*/ 0x78,0x00, /* .####........... */
+ /*0746:*/ 0x3e,0x00, /* ..#####......... */
+ /*0748:*/ 0x1f,0xe0, /* ...########..... */
+ /*074a:*/ 0x03,0xf8, /* ......#######... */
+ /*074c:*/ 0x00,0x7c, /* .........#####.. */
+ /*074e:*/ 0x00,0x1e, /* ...........####. */
+ /*0750:*/ 0x00,0x0e, /* ............###. */
+ /*0752:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0754:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0756:*/ 0xf0,0x1e, /* ####.......####. */
+ /*0758:*/ 0x7c,0x7c, /* .#####...#####.. */
+ /*075a:*/ 0x3f,0xf8, /* ..###########... */
+ /*075c:*/ 0x0f,0xe0, /* ....#######..... */
+/* --- new character T (84) starting at offset 0x075e --- */
+ /*075e:*/ 15, 15, 19, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0763:*/ 0xff,0xfe, /* ###############. */
+ /*0765:*/ 0xff,0xfe, /* ###############. */
+ /*0767:*/ 0x03,0x80, /* ......###....... */
+ /*0769:*/ 0x03,0x80, /* ......###....... */
+ /*076b:*/ 0x03,0x80, /* ......###....... */
+ /*076d:*/ 0x03,0x80, /* ......###....... */
+ /*076f:*/ 0x03,0x80, /* ......###....... */
+ /*0771:*/ 0x03,0x80, /* ......###....... */
+ /*0773:*/ 0x03,0x80, /* ......###....... */
+ /*0775:*/ 0x03,0x80, /* ......###....... */
+ /*0777:*/ 0x03,0x80, /* ......###....... */
+ /*0779:*/ 0x03,0x80, /* ......###....... */
+ /*077b:*/ 0x03,0x80, /* ......###....... */
+ /*077d:*/ 0x03,0x80, /* ......###....... */
+ /*077f:*/ 0x03,0x80, /* ......###....... */
+ /*0781:*/ 0x03,0x80, /* ......###....... */
+ /*0783:*/ 0x03,0x80, /* ......###....... */
+ /*0785:*/ 0x03,0x80, /* ......###....... */
+ /*0787:*/ 0x03,0x80, /* ......###....... */
+/* --- new character U (85) starting at offset 0x0789 --- */
+ /*0789:*/ 19, 15, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*078e:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0790:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0792:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0794:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0796:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0798:*/ 0xe0,0x0e, /* ###.........###. */
+ /*079a:*/ 0xe0,0x0e, /* ###.........###. */
+ /*079c:*/ 0xe0,0x0e, /* ###.........###. */
+ /*079e:*/ 0xe0,0x0e, /* ###.........###. */
+ /*07a0:*/ 0xe0,0x0e, /* ###.........###. */
+ /*07a2:*/ 0xe0,0x0e, /* ###.........###. */
+ /*07a4:*/ 0xe0,0x0e, /* ###.........###. */
+ /*07a6:*/ 0xe0,0x0e, /* ###.........###. */
+ /*07a8:*/ 0xe0,0x0e, /* ###.........###. */
+ /*07aa:*/ 0xf0,0x1e, /* ####.......####. */
+ /*07ac:*/ 0x70,0x1c, /* .###.......###.. */
+ /*07ae:*/ 0x7c,0x7c, /* .#####...#####.. */
+ /*07b0:*/ 0x3f,0xf8, /* ..###########... */
+ /*07b2:*/ 0x0f,0xe0, /* ....#######..... */
+/* --- new character V (86) starting at offset 0x07b4 --- */
+ /*07b4:*/ 18, 16, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*07b9:*/ 0xe0,0x07, /* ###..........### */
+ /*07bb:*/ 0xe0,0x07, /* ###..........### */
+ /*07bd:*/ 0xf0,0x0f, /* ####........#### */
+ /*07bf:*/ 0x70,0x0e, /* .###........###. */
+ /*07c1:*/ 0x78,0x1e, /* .####......####. */
+ /*07c3:*/ 0x38,0x1c, /* ..###......###.. */
+ /*07c5:*/ 0x38,0x1c, /* ..###......###.. */
+ /*07c7:*/ 0x3c,0x3c, /* ..####....####.. */
+ /*07c9:*/ 0x1c,0x38, /* ...###....###... */
+ /*07cb:*/ 0x1c,0x38, /* ...###....###... */
+ /*07cd:*/ 0x1e,0x78, /* ...####..####... */
+ /*07cf:*/ 0x0e,0x70, /* ....###..###.... */
+ /*07d1:*/ 0x0e,0x70, /* ....###..###.... */
+ /*07d3:*/ 0x0e,0x70, /* ....###..###.... */
+ /*07d5:*/ 0x07,0xe0, /* .....######..... */
+ /*07d7:*/ 0x07,0xe0, /* .....######..... */
+ /*07d9:*/ 0x03,0xc0, /* ......####...... */
+ /*07db:*/ 0x03,0xc0, /* ......####...... */
+ /*07dd:*/ 0x03,0xc0, /* ......####...... */
+/* --- new character W (87) starting at offset 0x07df --- */
+ /*07df:*/ 23, 21, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*07e4:*/ 0xe0,0x70,0x38, /* ###......###......###... */
+ /*07e7:*/ 0xe0,0x70,0x38, /* ###......###......###... */
+ /*07ea:*/ 0xe0,0x70,0x38, /* ###......###......###... */
+ /*07ed:*/ 0xe0,0x70,0x38, /* ###......###......###... */
+ /*07f0:*/ 0x70,0xf8,0x70, /* .###....#####....###.... */
+ /*07f3:*/ 0x70,0xf8,0x70, /* .###....#####....###.... */
+ /*07f6:*/ 0x70,0xd8,0x70, /* .###....##.##....###.... */
+ /*07f9:*/ 0x71,0xdc,0x70, /* .###...###.###...###.... */
+ /*07fc:*/ 0x31,0xdc,0x60, /* ..##...###.###...##..... */
+ /*07ff:*/ 0x39,0xdc,0xe0, /* ..###..###.###..###..... */
+ /*0802:*/ 0x39,0x8c,0xe0, /* ..###..##...##..###..... */
+ /*0805:*/ 0x3b,0x8e,0xe0, /* ..###.###...###.###..... */
+ /*0808:*/ 0x1b,0x8e,0xc0, /* ...##.###...###.##...... */
+ /*080b:*/ 0x1b,0x8e,0xc0, /* ...##.###...###.##...... */
+ /*080e:*/ 0x1f,0x07,0xc0, /* ...#####.....#####...... */
+ /*0811:*/ 0x1f,0x07,0xc0, /* ...#####.....#####...... */
+ /*0814:*/ 0x0e,0x03,0x80, /* ....###.......###....... */
+ /*0817:*/ 0x0e,0x03,0x80, /* ....###.......###....... */
+ /*081a:*/ 0x0e,0x03,0x80, /* ....###.......###....... */
+/* --- new character X (88) starting at offset 0x081d --- */
+ /*081d:*/ 18, 16, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0822:*/ 0xe0,0x07, /* ###..........### */
+ /*0824:*/ 0xf0,0x0f, /* ####........#### */
+ /*0826:*/ 0x78,0x1e, /* .####......####. */
+ /*0828:*/ 0x38,0x1c, /* ..###......###.. */
+ /*082a:*/ 0x1c,0x38, /* ...###....###... */
+ /*082c:*/ 0x0e,0x70, /* ....###..###.... */
+ /*082e:*/ 0x0f,0xf0, /* ....########.... */
+ /*0830:*/ 0x07,0xe0, /* .....######..... */
+ /*0832:*/ 0x03,0xc0, /* ......####...... */
+ /*0834:*/ 0x03,0xc0, /* ......####...... */
+ /*0836:*/ 0x07,0xe0, /* .....######..... */
+ /*0838:*/ 0x0f,0xf0, /* ....########.... */
+ /*083a:*/ 0x0e,0x70, /* ....###..###.... */
+ /*083c:*/ 0x1c,0x38, /* ...###....###... */
+ /*083e:*/ 0x3c,0x3c, /* ..####....####.. */
+ /*0840:*/ 0x38,0x1c, /* ..###......###.. */
+ /*0842:*/ 0x70,0x0e, /* .###........###. */
+ /*0844:*/ 0xf0,0x0f, /* ####........#### */
+ /*0846:*/ 0xe0,0x07, /* ###..........### */
+/* --- new character Y (89) starting at offset 0x0848 --- */
+ /*0848:*/ 17, 15, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*084d:*/ 0xe0,0x0e, /* ###.........###. */
+ /*084f:*/ 0xf0,0x1e, /* ####.......####. */
+ /*0851:*/ 0x70,0x1c, /* .###.......###.. */
+ /*0853:*/ 0x78,0x3c, /* .####.....####.. */
+ /*0855:*/ 0x38,0x38, /* ..###.....###... */
+ /*0857:*/ 0x3c,0x78, /* ..####...####... */
+ /*0859:*/ 0x1c,0x70, /* ...###...###.... */
+ /*085b:*/ 0x1e,0xf0, /* ...####.####.... */
+ /*085d:*/ 0x0e,0xe0, /* ....###.###..... */
+ /*085f:*/ 0x0f,0xe0, /* ....#######..... */
+ /*0861:*/ 0x07,0xc0, /* .....#####...... */
+ /*0863:*/ 0x07,0xc0, /* .....#####...... */
+ /*0865:*/ 0x03,0x80, /* ......###....... */
+ /*0867:*/ 0x03,0x80, /* ......###....... */
+ /*0869:*/ 0x03,0x80, /* ......###....... */
+ /*086b:*/ 0x03,0x80, /* ......###....... */
+ /*086d:*/ 0x03,0x80, /* ......###....... */
+ /*086f:*/ 0x03,0x80, /* ......###....... */
+ /*0871:*/ 0x03,0x80, /* ......###....... */
+/* --- new character Z (90) starting at offset 0x0873 --- */
+ /*0873:*/ 16, 14, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0878:*/ 0xff,0xfc, /* ##############.. */
+ /*087a:*/ 0xff,0xfc, /* ##############.. */
+ /*087c:*/ 0x00,0x3c, /* ..........####.. */
+ /*087e:*/ 0x00,0x78, /* .........####... */
+ /*0880:*/ 0x00,0xf0, /* ........####.... */
+ /*0882:*/ 0x01,0xe0, /* .......####..... */
+ /*0884:*/ 0x01,0xe0, /* .......####..... */
+ /*0886:*/ 0x03,0xc0, /* ......####...... */
+ /*0888:*/ 0x07,0x80, /* .....####....... */
+ /*088a:*/ 0x07,0x80, /* .....####....... */
+ /*088c:*/ 0x0f,0x00, /* ....####........ */
+ /*088e:*/ 0x1e,0x00, /* ...####......... */
+ /*0890:*/ 0x1e,0x00, /* ...####......... */
+ /*0892:*/ 0x3c,0x00, /* ..####.......... */
+ /*0894:*/ 0x38,0x00, /* ..###........... */
+ /*0896:*/ 0x78,0x00, /* .####........... */
+ /*0898:*/ 0xf0,0x00, /* ####............ */
+ /*089a:*/ 0xff,0xfc, /* ##############.. */
+ /*089c:*/ 0xff,0xfc, /* ##############.. */
+/* --- new character bracketleft (91) starting at offset 0x089e --- */
+ /*089e:*/ 8, 5, 24, 1, -5, /* width and bbox (w,h,x,y) */
+ /*08a3:*/ 0xf8, /* #####... */
+ /*08a4:*/ 0xf8, /* #####... */
+ /*08a5:*/ 0xe0, /* ###..... */
+ /*08a6:*/ 0xe0, /* ###..... */
+ /*08a7:*/ 0xe0, /* ###..... */
+ /*08a8:*/ 0xe0, /* ###..... */
+ /*08a9:*/ 0xe0, /* ###..... */
+ /*08aa:*/ 0xe0, /* ###..... */
+ /*08ab:*/ 0xe0, /* ###..... */
+ /*08ac:*/ 0xe0, /* ###..... */
+ /*08ad:*/ 0xe0, /* ###..... */
+ /*08ae:*/ 0xe0, /* ###..... */
+ /*08af:*/ 0xe0, /* ###..... */
+ /*08b0:*/ 0xe0, /* ###..... */
+ /*08b1:*/ 0xe0, /* ###..... */
+ /*08b2:*/ 0xe0, /* ###..... */
+ /*08b3:*/ 0xe0, /* ###..... */
+ /*08b4:*/ 0xe0, /* ###..... */
+ /*08b5:*/ 0xe0, /* ###..... */
+ /*08b6:*/ 0xe0, /* ###..... */
+ /*08b7:*/ 0xe0, /* ###..... */
+ /*08b8:*/ 0xe0, /* ###..... */
+ /*08b9:*/ 0xf8, /* #####... */
+ /*08ba:*/ 0xf8, /* #####... */
+/* --- new character backslash (92) starting at offset 0x08bb --- */
+ /*08bb:*/ 8, 8, 19, 0, 0, /* width and bbox (w,h,x,y) */
+ /*08c0:*/ 0xe0, /* ###..... */
+ /*08c1:*/ 0xe0, /* ###..... */
+ /*08c2:*/ 0x60, /* .##..... */
+ /*08c3:*/ 0x60, /* .##..... */
+ /*08c4:*/ 0x70, /* .###.... */
+ /*08c5:*/ 0x30, /* ..##.... */
+ /*08c6:*/ 0x30, /* ..##.... */
+ /*08c7:*/ 0x38, /* ..###... */
+ /*08c8:*/ 0x38, /* ..###... */
+ /*08c9:*/ 0x18, /* ...##... */
+ /*08ca:*/ 0x18, /* ...##... */
+ /*08cb:*/ 0x1c, /* ...###.. */
+ /*08cc:*/ 0x0c, /* ....##.. */
+ /*08cd:*/ 0x0c, /* ....##.. */
+ /*08ce:*/ 0x0e, /* ....###. */
+ /*08cf:*/ 0x06, /* .....##. */
+ /*08d0:*/ 0x06, /* .....##. */
+ /*08d1:*/ 0x07, /* .....### */
+ /*08d2:*/ 0x07, /* .....### */
+/* --- new character bracketright (93) starting at offset 0x08d3 --- */
+ /*08d3:*/ 8, 5, 24, 2, -5, /* width and bbox (w,h,x,y) */
+ /*08d8:*/ 0xf8, /* #####... */
+ /*08d9:*/ 0xf8, /* #####... */
+ /*08da:*/ 0x38, /* ..###... */
+ /*08db:*/ 0x38, /* ..###... */
+ /*08dc:*/ 0x38, /* ..###... */
+ /*08dd:*/ 0x38, /* ..###... */
+ /*08de:*/ 0x38, /* ..###... */
+ /*08df:*/ 0x38, /* ..###... */
+ /*08e0:*/ 0x38, /* ..###... */
+ /*08e1:*/ 0x38, /* ..###... */
+ /*08e2:*/ 0x38, /* ..###... */
+ /*08e3:*/ 0x38, /* ..###... */
+ /*08e4:*/ 0x38, /* ..###... */
+ /*08e5:*/ 0x38, /* ..###... */
+ /*08e6:*/ 0x38, /* ..###... */
+ /*08e7:*/ 0x38, /* ..###... */
+ /*08e8:*/ 0x38, /* ..###... */
+ /*08e9:*/ 0x38, /* ..###... */
+ /*08ea:*/ 0x38, /* ..###... */
+ /*08eb:*/ 0x38, /* ..###... */
+ /*08ec:*/ 0x38, /* ..###... */
+ /*08ed:*/ 0x38, /* ..###... */
+ /*08ee:*/ 0xf8, /* #####... */
+ /*08ef:*/ 0xf8, /* #####... */
+/* --- new character asciicircum (94) starting at offset 0x08f0 --- */
+ /*08f0:*/ 14, 11, 9, 1, 10, /* width and bbox (w,h,x,y) */
+ /*08f5:*/ 0x0e,0x00, /* ....###......... */
+ /*08f7:*/ 0x0e,0x00, /* ....###......... */
+ /*08f9:*/ 0x1f,0x00, /* ...#####........ */
+ /*08fb:*/ 0x1b,0x00, /* ...##.##........ */
+ /*08fd:*/ 0x3b,0x80, /* ..###.###....... */
+ /*08ff:*/ 0x71,0xc0, /* .###...###...... */
+ /*0901:*/ 0x71,0xc0, /* .###...###...... */
+ /*0903:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0905:*/ 0xe0,0xe0, /* ###.....###..... */
+/* --- new character underscore (95) starting at offset 0x0907 --- */
+ /*0907:*/ 14, 14, 2, 0, -5, /* width and bbox (w,h,x,y) */
+ /*090c:*/ 0xff,0xfc, /* ##############.. */
+ /*090e:*/ 0xff,0xfc, /* ##############.. */
+/* --- new character grave (96) starting at offset 0x0910 --- */
+ /*0910:*/ 8, 6, 4, 1, 15, /* width and bbox (w,h,x,y) */
+ /*0915:*/ 0xe0, /* ###..... */
+ /*0916:*/ 0x70, /* .###.... */
+ /*0917:*/ 0x38, /* ..###... */
+ /*0918:*/ 0x1c, /* ...###.. */
+/* --- new character a (97) starting at offset 0x0919 --- */
+ /*0919:*/ 14, 12, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*091e:*/ 0x1f,0x80, /* ...######....... */
+ /*0920:*/ 0x3f,0xc0, /* ..########...... */
+ /*0922:*/ 0x71,0xe0, /* .###...####..... */
+ /*0924:*/ 0x70,0xe0, /* .###....###..... */
+ /*0926:*/ 0x00,0xe0, /* ........###..... */
+ /*0928:*/ 0x07,0xe0, /* .....######..... */
+ /*092a:*/ 0x3f,0xe0, /* ..#########..... */
+ /*092c:*/ 0x7c,0xe0, /* .#####..###..... */
+ /*092e:*/ 0xf0,0xe0, /* ####....###..... */
+ /*0930:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0932:*/ 0xe1,0xe0, /* ###....####..... */
+ /*0934:*/ 0xf3,0xe0, /* ####..#####..... */
+ /*0936:*/ 0x7f,0xf0, /* .###########.... */
+ /*0938:*/ 0x3e,0x70, /* ..#####..###.... */
+/* --- new character b (98) starting at offset 0x093a --- */
+ /*093a:*/ 15, 12, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*093f:*/ 0xe0,0x00, /* ###............. */
+ /*0941:*/ 0xe0,0x00, /* ###............. */
+ /*0943:*/ 0xe0,0x00, /* ###............. */
+ /*0945:*/ 0xe0,0x00, /* ###............. */
+ /*0947:*/ 0xe0,0x00, /* ###............. */
+ /*0949:*/ 0xef,0x80, /* ###.#####....... */
+ /*094b:*/ 0xff,0xc0, /* ##########...... */
+ /*094d:*/ 0xf9,0xe0, /* #####..####..... */
+ /*094f:*/ 0xf0,0xe0, /* ####....###..... */
+ /*0951:*/ 0xe0,0x70, /* ###......###.... */
+ /*0953:*/ 0xe0,0x70, /* ###......###.... */
+ /*0955:*/ 0xe0,0x70, /* ###......###.... */
+ /*0957:*/ 0xe0,0x70, /* ###......###.... */
+ /*0959:*/ 0xe0,0x70, /* ###......###.... */
+ /*095b:*/ 0xe0,0x70, /* ###......###.... */
+ /*095d:*/ 0xf0,0xe0, /* ####....###..... */
+ /*095f:*/ 0xf9,0xe0, /* #####..####..... */
+ /*0961:*/ 0xff,0xc0, /* ##########...... */
+ /*0963:*/ 0xef,0x80, /* ###.#####....... */
+/* --- new character c (99) starting at offset 0x0965 --- */
+ /*0965:*/ 13, 11, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*096a:*/ 0x1f,0x80, /* ...######....... */
+ /*096c:*/ 0x3f,0xc0, /* ..########...... */
+ /*096e:*/ 0x79,0xe0, /* .####..####..... */
+ /*0970:*/ 0x70,0xe0, /* .###....###..... */
+ /*0972:*/ 0xe0,0x00, /* ###............. */
+ /*0974:*/ 0xe0,0x00, /* ###............. */
+ /*0976:*/ 0xe0,0x00, /* ###............. */
+ /*0978:*/ 0xe0,0x00, /* ###............. */
+ /*097a:*/ 0xe0,0x00, /* ###............. */
+ /*097c:*/ 0xe0,0x00, /* ###............. */
+ /*097e:*/ 0x70,0xe0, /* .###....###..... */
+ /*0980:*/ 0x79,0xe0, /* .####..####..... */
+ /*0982:*/ 0x3f,0xc0, /* ..########...... */
+ /*0984:*/ 0x1f,0x80, /* ...######....... */
+/* --- new character d (100) starting at offset 0x0986 --- */
+ /*0986:*/ 15, 12, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*098b:*/ 0x00,0x70, /* .........###.... */
+ /*098d:*/ 0x00,0x70, /* .........###.... */
+ /*098f:*/ 0x00,0x70, /* .........###.... */
+ /*0991:*/ 0x00,0x70, /* .........###.... */
+ /*0993:*/ 0x00,0x70, /* .........###.... */
+ /*0995:*/ 0x1f,0x70, /* ...#####.###.... */
+ /*0997:*/ 0x3f,0xf0, /* ..##########.... */
+ /*0999:*/ 0x79,0xf0, /* .####..#####.... */
+ /*099b:*/ 0x70,0xf0, /* .###....####.... */
+ /*099d:*/ 0xe0,0x70, /* ###......###.... */
+ /*099f:*/ 0xe0,0x70, /* ###......###.... */
+ /*09a1:*/ 0xe0,0x70, /* ###......###.... */
+ /*09a3:*/ 0xe0,0x70, /* ###......###.... */
+ /*09a5:*/ 0xe0,0x70, /* ###......###.... */
+ /*09a7:*/ 0xe0,0x70, /* ###......###.... */
+ /*09a9:*/ 0x70,0xf0, /* .###....####.... */
+ /*09ab:*/ 0x79,0xf0, /* .####..#####.... */
+ /*09ad:*/ 0x3f,0xf0, /* ..##########.... */
+ /*09af:*/ 0x1f,0x70, /* ...#####.###.... */
+/* --- new character e (101) starting at offset 0x09b1 --- */
+ /*09b1:*/ 14, 12, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*09b6:*/ 0x0f,0x00, /* ....####........ */
+ /*09b8:*/ 0x3f,0xc0, /* ..########...... */
+ /*09ba:*/ 0x79,0xe0, /* .####..####..... */
+ /*09bc:*/ 0x70,0xe0, /* .###....###..... */
+ /*09be:*/ 0xe0,0x70, /* ###......###.... */
+ /*09c0:*/ 0xe0,0x70, /* ###......###.... */
+ /*09c2:*/ 0xff,0xf0, /* ############.... */
+ /*09c4:*/ 0xff,0xf0, /* ############.... */
+ /*09c6:*/ 0xe0,0x00, /* ###............. */
+ /*09c8:*/ 0xe0,0x00, /* ###............. */
+ /*09ca:*/ 0x70,0x70, /* .###.....###.... */
+ /*09cc:*/ 0x78,0xf0, /* .####...####.... */
+ /*09ce:*/ 0x3f,0xe0, /* ..#########..... */
+ /*09d0:*/ 0x0f,0x80, /* ....#####....... */
+/* --- new character f (102) starting at offset 0x09d2 --- */
+ /*09d2:*/ 9, 7, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*09d7:*/ 0x1e, /* ...####. */
+ /*09d8:*/ 0x3e, /* ..#####. */
+ /*09d9:*/ 0x38, /* ..###... */
+ /*09da:*/ 0x38, /* ..###... */
+ /*09db:*/ 0x38, /* ..###... */
+ /*09dc:*/ 0xfe, /* #######. */
+ /*09dd:*/ 0xfe, /* #######. */
+ /*09de:*/ 0x38, /* ..###... */
+ /*09df:*/ 0x38, /* ..###... */
+ /*09e0:*/ 0x38, /* ..###... */
+ /*09e1:*/ 0x38, /* ..###... */
+ /*09e2:*/ 0x38, /* ..###... */
+ /*09e3:*/ 0x38, /* ..###... */
+ /*09e4:*/ 0x38, /* ..###... */
+ /*09e5:*/ 0x38, /* ..###... */
+ /*09e6:*/ 0x38, /* ..###... */
+ /*09e7:*/ 0x38, /* ..###... */
+ /*09e8:*/ 0x38, /* ..###... */
+ /*09e9:*/ 0x38, /* ..###... */
+/* --- new character g (103) starting at offset 0x09ea --- */
+ /*09ea:*/ 15, 12, 19, 1, -5, /* width and bbox (w,h,x,y) */
+ /*09ef:*/ 0x1f,0x70, /* ...#####.###.... */
+ /*09f1:*/ 0x3f,0xf0, /* ..##########.... */
+ /*09f3:*/ 0x79,0xf0, /* .####..#####.... */
+ /*09f5:*/ 0x70,0xf0, /* .###....####.... */
+ /*09f7:*/ 0xe0,0x70, /* ###......###.... */
+ /*09f9:*/ 0xe0,0x70, /* ###......###.... */
+ /*09fb:*/ 0xe0,0x70, /* ###......###.... */
+ /*09fd:*/ 0xe0,0x70, /* ###......###.... */
+ /*09ff:*/ 0xe0,0x70, /* ###......###.... */
+ /*0a01:*/ 0xe0,0x70, /* ###......###.... */
+ /*0a03:*/ 0x70,0xf0, /* .###....####.... */
+ /*0a05:*/ 0x79,0xf0, /* .####..#####.... */
+ /*0a07:*/ 0x3f,0xf0, /* ..##########.... */
+ /*0a09:*/ 0x1f,0x70, /* ...#####.###.... */
+ /*0a0b:*/ 0x00,0x70, /* .........###.... */
+ /*0a0d:*/ 0xe0,0x70, /* ###......###.... */
+ /*0a0f:*/ 0xf0,0xe0, /* ####....###..... */
+ /*0a11:*/ 0x7f,0xe0, /* .##########..... */
+ /*0a13:*/ 0x1f,0x80, /* ...######....... */
+/* --- new character h (104) starting at offset 0x0a15 --- */
+ /*0a15:*/ 15, 11, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0a1a:*/ 0xe0,0x00, /* ###............. */
+ /*0a1c:*/ 0xe0,0x00, /* ###............. */
+ /*0a1e:*/ 0xe0,0x00, /* ###............. */
+ /*0a20:*/ 0xe0,0x00, /* ###............. */
+ /*0a22:*/ 0xe0,0x00, /* ###............. */
+ /*0a24:*/ 0xef,0x00, /* ###.####........ */
+ /*0a26:*/ 0xff,0xc0, /* ##########...... */
+ /*0a28:*/ 0xf1,0xc0, /* ####...###...... */
+ /*0a2a:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a2c:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a2e:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a30:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a32:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a34:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a36:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a38:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a3a:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a3c:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0a3e:*/ 0xe0,0xe0, /* ###.....###..... */
+/* --- new character i (105) starting at offset 0x0a40 --- */
+ /*0a40:*/ 7, 3, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0a45:*/ 0xe0, /* ###..... */
+ /*0a46:*/ 0xe0, /* ###..... */
+ /*0a47:*/ 0xe0, /* ###..... */
+ /*0a48:*/ 0x00, /* ........ */
+ /*0a49:*/ 0x00, /* ........ */
+ /*0a4a:*/ 0xe0, /* ###..... */
+ /*0a4b:*/ 0xe0, /* ###..... */
+ /*0a4c:*/ 0xe0, /* ###..... */
+ /*0a4d:*/ 0xe0, /* ###..... */
+ /*0a4e:*/ 0xe0, /* ###..... */
+ /*0a4f:*/ 0xe0, /* ###..... */
+ /*0a50:*/ 0xe0, /* ###..... */
+ /*0a51:*/ 0xe0, /* ###..... */
+ /*0a52:*/ 0xe0, /* ###..... */
+ /*0a53:*/ 0xe0, /* ###..... */
+ /*0a54:*/ 0xe0, /* ###..... */
+ /*0a55:*/ 0xe0, /* ###..... */
+ /*0a56:*/ 0xe0, /* ###..... */
+ /*0a57:*/ 0xe0, /* ###..... */
+/* --- new character j (106) starting at offset 0x0a58 --- */
+ /*0a58:*/ 7, 5, 24, 0, -5, /* width and bbox (w,h,x,y) */
+ /*0a5d:*/ 0x38, /* ..###... */
+ /*0a5e:*/ 0x38, /* ..###... */
+ /*0a5f:*/ 0x38, /* ..###... */
+ /*0a60:*/ 0x00, /* ........ */
+ /*0a61:*/ 0x00, /* ........ */
+ /*0a62:*/ 0x38, /* ..###... */
+ /*0a63:*/ 0x38, /* ..###... */
+ /*0a64:*/ 0x38, /* ..###... */
+ /*0a65:*/ 0x38, /* ..###... */
+ /*0a66:*/ 0x38, /* ..###... */
+ /*0a67:*/ 0x38, /* ..###... */
+ /*0a68:*/ 0x38, /* ..###... */
+ /*0a69:*/ 0x38, /* ..###... */
+ /*0a6a:*/ 0x38, /* ..###... */
+ /*0a6b:*/ 0x38, /* ..###... */
+ /*0a6c:*/ 0x38, /* ..###... */
+ /*0a6d:*/ 0x38, /* ..###... */
+ /*0a6e:*/ 0x38, /* ..###... */
+ /*0a6f:*/ 0x38, /* ..###... */
+ /*0a70:*/ 0x38, /* ..###... */
+ /*0a71:*/ 0x38, /* ..###... */
+ /*0a72:*/ 0x38, /* ..###... */
+ /*0a73:*/ 0xf8, /* #####... */
+ /*0a74:*/ 0xf0, /* ####.... */
+/* --- new character k (107) starting at offset 0x0a75 --- */
+ /*0a75:*/ 14, 12, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0a7a:*/ 0xe0,0x00, /* ###............. */
+ /*0a7c:*/ 0xe0,0x00, /* ###............. */
+ /*0a7e:*/ 0xe0,0x00, /* ###............. */
+ /*0a80:*/ 0xe0,0x00, /* ###............. */
+ /*0a82:*/ 0xe0,0x00, /* ###............. */
+ /*0a84:*/ 0xe1,0xe0, /* ###....####..... */
+ /*0a86:*/ 0xe3,0xc0, /* ###...####...... */
+ /*0a88:*/ 0xe7,0x80, /* ###..####....... */
+ /*0a8a:*/ 0xef,0x00, /* ###.####........ */
+ /*0a8c:*/ 0xfe,0x00, /* #######......... */
+ /*0a8e:*/ 0xfc,0x00, /* ######.......... */
+ /*0a90:*/ 0xfe,0x00, /* #######......... */
+ /*0a92:*/ 0xef,0x00, /* ###.####........ */
+ /*0a94:*/ 0xe7,0x00, /* ###..###........ */
+ /*0a96:*/ 0xe7,0x80, /* ###..####....... */
+ /*0a98:*/ 0xe3,0xc0, /* ###...####...... */
+ /*0a9a:*/ 0xe1,0xc0, /* ###....###...... */
+ /*0a9c:*/ 0xe1,0xe0, /* ###....####..... */
+ /*0a9e:*/ 0xe0,0xf0, /* ###.....####.... */
+/* --- new character l (108) starting at offset 0x0aa0 --- */
+ /*0aa0:*/ 7, 3, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0aa5:*/ 0xe0, /* ###..... */
+ /*0aa6:*/ 0xe0, /* ###..... */
+ /*0aa7:*/ 0xe0, /* ###..... */
+ /*0aa8:*/ 0xe0, /* ###..... */
+ /*0aa9:*/ 0xe0, /* ###..... */
+ /*0aaa:*/ 0xe0, /* ###..... */
+ /*0aab:*/ 0xe0, /* ###..... */
+ /*0aac:*/ 0xe0, /* ###..... */
+ /*0aad:*/ 0xe0, /* ###..... */
+ /*0aae:*/ 0xe0, /* ###..... */
+ /*0aaf:*/ 0xe0, /* ###..... */
+ /*0ab0:*/ 0xe0, /* ###..... */
+ /*0ab1:*/ 0xe0, /* ###..... */
+ /*0ab2:*/ 0xe0, /* ###..... */
+ /*0ab3:*/ 0xe0, /* ###..... */
+ /*0ab4:*/ 0xe0, /* ###..... */
+ /*0ab5:*/ 0xe0, /* ###..... */
+ /*0ab6:*/ 0xe0, /* ###..... */
+ /*0ab7:*/ 0xe0, /* ###..... */
+/* --- new character m (109) starting at offset 0x0ab8 --- */
+ /*0ab8:*/ 21, 17, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0abd:*/ 0xef,0x3e,0x00, /* ###.####..#####......... */
+ /*0ac0:*/ 0xff,0xff,0x00, /* ################........ */
+ /*0ac3:*/ 0xf3,0xe7,0x80, /* ####..#####..####....... */
+ /*0ac6:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0ac9:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0acc:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0acf:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0ad2:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0ad5:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0ad8:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0adb:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0ade:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0ae1:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+ /*0ae4:*/ 0xe1,0xc3,0x80, /* ###....###....###....... */
+/* --- new character n (110) starting at offset 0x0ae7 --- */
+ /*0ae7:*/ 15, 11, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0aec:*/ 0xef,0x80, /* ###.#####....... */
+ /*0aee:*/ 0xff,0xc0, /* ##########...... */
+ /*0af0:*/ 0xf1,0xc0, /* ####...###...... */
+ /*0af2:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0af4:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0af6:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0af8:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0afa:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0afc:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0afe:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0b00:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0b02:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0b04:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0b06:*/ 0xe0,0xe0, /* ###.....###..... */
+/* --- new character o (111) starting at offset 0x0b08 --- */
+ /*0b08:*/ 14, 12, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0b0d:*/ 0x0f,0x00, /* ....####........ */
+ /*0b0f:*/ 0x3f,0xc0, /* ..########...... */
+ /*0b11:*/ 0x79,0xe0, /* .####..####..... */
+ /*0b13:*/ 0x70,0xe0, /* .###....###..... */
+ /*0b15:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b17:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b19:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b1b:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b1d:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b1f:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b21:*/ 0x70,0xe0, /* .###....###..... */
+ /*0b23:*/ 0x79,0xe0, /* .####..####..... */
+ /*0b25:*/ 0x3f,0xc0, /* ..########...... */
+ /*0b27:*/ 0x0f,0x00, /* ....####........ */
+/* --- new character p (112) starting at offset 0x0b29 --- */
+ /*0b29:*/ 15, 12, 19, 2, -5, /* width and bbox (w,h,x,y) */
+ /*0b2e:*/ 0xef,0x80, /* ###.#####....... */
+ /*0b30:*/ 0xff,0xc0, /* ##########...... */
+ /*0b32:*/ 0xf9,0xe0, /* #####..####..... */
+ /*0b34:*/ 0xf0,0xe0, /* ####....###..... */
+ /*0b36:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b38:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b3a:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b3c:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b3e:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b40:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b42:*/ 0xf0,0xe0, /* ####....###..... */
+ /*0b44:*/ 0xf9,0xe0, /* #####..####..... */
+ /*0b46:*/ 0xff,0xc0, /* ##########...... */
+ /*0b48:*/ 0xef,0x80, /* ###.#####....... */
+ /*0b4a:*/ 0xe0,0x00, /* ###............. */
+ /*0b4c:*/ 0xe0,0x00, /* ###............. */
+ /*0b4e:*/ 0xe0,0x00, /* ###............. */
+ /*0b50:*/ 0xe0,0x00, /* ###............. */
+ /*0b52:*/ 0xe0,0x00, /* ###............. */
+/* --- new character q (113) starting at offset 0x0b54 --- */
+ /*0b54:*/ 15, 12, 19, 1, -5, /* width and bbox (w,h,x,y) */
+ /*0b59:*/ 0x1f,0x70, /* ...#####.###.... */
+ /*0b5b:*/ 0x3f,0xf0, /* ..##########.... */
+ /*0b5d:*/ 0x79,0xf0, /* .####..#####.... */
+ /*0b5f:*/ 0x70,0xf0, /* .###....####.... */
+ /*0b61:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b63:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b65:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b67:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b69:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b6b:*/ 0xe0,0x70, /* ###......###.... */
+ /*0b6d:*/ 0x70,0xf0, /* .###....####.... */
+ /*0b6f:*/ 0x79,0xf0, /* .####..#####.... */
+ /*0b71:*/ 0x3f,0xf0, /* ..##########.... */
+ /*0b73:*/ 0x1f,0x70, /* ...#####.###.... */
+ /*0b75:*/ 0x00,0x70, /* .........###.... */
+ /*0b77:*/ 0x00,0x70, /* .........###.... */
+ /*0b79:*/ 0x00,0x70, /* .........###.... */
+ /*0b7b:*/ 0x00,0x70, /* .........###.... */
+ /*0b7d:*/ 0x00,0x70, /* .........###.... */
+/* --- new character r (114) starting at offset 0x0b7f --- */
+ /*0b7f:*/ 10, 7, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0b84:*/ 0xe6, /* ###..##. */
+ /*0b85:*/ 0xee, /* ###.###. */
+ /*0b86:*/ 0xfe, /* #######. */
+ /*0b87:*/ 0xf0, /* ####.... */
+ /*0b88:*/ 0xe0, /* ###..... */
+ /*0b89:*/ 0xe0, /* ###..... */
+ /*0b8a:*/ 0xe0, /* ###..... */
+ /*0b8b:*/ 0xe0, /* ###..... */
+ /*0b8c:*/ 0xe0, /* ###..... */
+ /*0b8d:*/ 0xe0, /* ###..... */
+ /*0b8e:*/ 0xe0, /* ###..... */
+ /*0b8f:*/ 0xe0, /* ###..... */
+ /*0b90:*/ 0xe0, /* ###..... */
+ /*0b91:*/ 0xe0, /* ###..... */
+/* --- new character s (115) starting at offset 0x0b92 --- */
+ /*0b92:*/ 13, 11, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0b97:*/ 0x3f,0x00, /* ..######........ */
+ /*0b99:*/ 0x7f,0x80, /* .########....... */
+ /*0b9b:*/ 0xf3,0xc0, /* ####..####...... */
+ /*0b9d:*/ 0xe1,0xc0, /* ###....###...... */
+ /*0b9f:*/ 0xe0,0x00, /* ###............. */
+ /*0ba1:*/ 0xfc,0x00, /* ######.......... */
+ /*0ba3:*/ 0x7f,0x80, /* .########....... */
+ /*0ba5:*/ 0x0f,0xc0, /* ....######...... */
+ /*0ba7:*/ 0x01,0xe0, /* .......####..... */
+ /*0ba9:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bab:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bad:*/ 0xf1,0xe0, /* ####...####..... */
+ /*0baf:*/ 0x7f,0xc0, /* .#########...... */
+ /*0bb1:*/ 0x3f,0x80, /* ..#######....... */
+/* --- new character t (116) starting at offset 0x0bb3 --- */
+ /*0bb3:*/ 9, 7, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0bb8:*/ 0x38, /* ..###... */
+ /*0bb9:*/ 0x38, /* ..###... */
+ /*0bba:*/ 0x38, /* ..###... */
+ /*0bbb:*/ 0x38, /* ..###... */
+ /*0bbc:*/ 0xfe, /* #######. */
+ /*0bbd:*/ 0xfe, /* #######. */
+ /*0bbe:*/ 0x38, /* ..###... */
+ /*0bbf:*/ 0x38, /* ..###... */
+ /*0bc0:*/ 0x38, /* ..###... */
+ /*0bc1:*/ 0x38, /* ..###... */
+ /*0bc2:*/ 0x38, /* ..###... */
+ /*0bc3:*/ 0x38, /* ..###... */
+ /*0bc4:*/ 0x38, /* ..###... */
+ /*0bc5:*/ 0x38, /* ..###... */
+ /*0bc6:*/ 0x38, /* ..###... */
+ /*0bc7:*/ 0x38, /* ..###... */
+ /*0bc8:*/ 0x3e, /* ..#####. */
+ /*0bc9:*/ 0x1e, /* ...####. */
+/* --- new character u (117) starting at offset 0x0bca --- */
+ /*0bca:*/ 15, 11, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0bcf:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bd1:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bd3:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bd5:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bd7:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bd9:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bdb:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bdd:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0bdf:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0be1:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0be3:*/ 0xe1,0xe0, /* ###....####..... */
+ /*0be5:*/ 0x73,0xe0, /* .###..#####..... */
+ /*0be7:*/ 0x7e,0xe0, /* .######.###..... */
+ /*0be9:*/ 0x1c,0xe0, /* ...###..###..... */
+/* --- new character v (118) starting at offset 0x0beb --- */
+ /*0beb:*/ 14, 12, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0bf0:*/ 0xe0,0x70, /* ###......###.... */
+ /*0bf2:*/ 0xe0,0x70, /* ###......###.... */
+ /*0bf4:*/ 0xe0,0x70, /* ###......###.... */
+ /*0bf6:*/ 0x70,0xe0, /* .###....###..... */
+ /*0bf8:*/ 0x70,0xe0, /* .###....###..... */
+ /*0bfa:*/ 0x70,0xe0, /* .###....###..... */
+ /*0bfc:*/ 0x39,0xc0, /* ..###..###...... */
+ /*0bfe:*/ 0x39,0xc0, /* ..###..###...... */
+ /*0c00:*/ 0x39,0xc0, /* ..###..###...... */
+ /*0c02:*/ 0x1f,0x80, /* ...######....... */
+ /*0c04:*/ 0x1f,0x80, /* ...######....... */
+ /*0c06:*/ 0x0f,0x00, /* ....####........ */
+ /*0c08:*/ 0x0f,0x00, /* ....####........ */
+ /*0c0a:*/ 0x0f,0x00, /* ....####........ */
+/* --- new character w (119) starting at offset 0x0c0c --- */
+ /*0c0c:*/ 19, 19, 14, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0c11:*/ 0xe0,0xe0,0xe0, /* ###.....###.....###..... */
+ /*0c14:*/ 0xe0,0xe0,0xe0, /* ###.....###.....###..... */
+ /*0c17:*/ 0x60,0xe0,0xc0, /* .##.....###.....##...... */
+ /*0c1a:*/ 0x71,0xf1,0xc0, /* .###...#####...###...... */
+ /*0c1d:*/ 0x71,0xf1,0xc0, /* .###...#####...###...... */
+ /*0c20:*/ 0x31,0xb1,0x80, /* ..##...##.##...##....... */
+ /*0c23:*/ 0x33,0xb9,0x80, /* ..##..###.###..##....... */
+ /*0c26:*/ 0x3b,0xbb,0x80, /* ..###.###.###.###....... */
+ /*0c29:*/ 0x1b,0x1b,0x00, /* ...##.##...##.##........ */
+ /*0c2c:*/ 0x1f,0x1f,0x00, /* ...#####...#####........ */
+ /*0c2f:*/ 0x1f,0x1f,0x00, /* ...#####...#####........ */
+ /*0c32:*/ 0x0e,0x0e,0x00, /* ....###.....###......... */
+ /*0c35:*/ 0x0e,0x0e,0x00, /* ....###.....###......... */
+ /*0c38:*/ 0x0e,0x0e,0x00, /* ....###.....###......... */
+/* --- new character x (120) starting at offset 0x0c3b --- */
+ /*0c3b:*/ 13, 11, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0c40:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*0c42:*/ 0xf1,0xe0, /* ####...####..... */
+ /*0c44:*/ 0x71,0xc0, /* .###...###...... */
+ /*0c46:*/ 0x3b,0x80, /* ..###.###....... */
+ /*0c48:*/ 0x3f,0x80, /* ..#######....... */
+ /*0c4a:*/ 0x1f,0x00, /* ...#####........ */
+ /*0c4c:*/ 0x0e,0x00, /* ....###......... */
+ /*0c4e:*/ 0x1f,0x00, /* ...#####........ */
+ /*0c50:*/ 0x1f,0x00, /* ...#####........ */
+ /*0c52:*/ 0x3b,0x80, /* ..###.###....... */
+ /*0c54:*/ 0x7b,0xc0, /* .####.####...... */
+ /*0c56:*/ 0x71,0xc0, /* .###...###...... */
+ /*0c58:*/ 0xf1,0xe0, /* ####...####..... */
+ /*0c5a:*/ 0xe0,0xe0, /* ###.....###..... */
+/* --- new character y (121) starting at offset 0x0c5c --- */
+ /*0c5c:*/ 15, 13, 19, 1, -5, /* width and bbox (w,h,x,y) */
+ /*0c61:*/ 0xe0,0x38, /* ###.......###... */
+ /*0c63:*/ 0xe0,0x38, /* ###.......###... */
+ /*0c65:*/ 0x70,0x38, /* .###......###... */
+ /*0c67:*/ 0x78,0x70, /* .####....###.... */
+ /*0c69:*/ 0x38,0x70, /* ..###....###.... */
+ /*0c6b:*/ 0x3c,0xf0, /* ..####..####.... */
+ /*0c6d:*/ 0x1c,0xe0, /* ...###..###..... */
+ /*0c6f:*/ 0x1c,0xe0, /* ...###..###..... */
+ /*0c71:*/ 0x0f,0xc0, /* ....######...... */
+ /*0c73:*/ 0x0f,0xc0, /* ....######...... */
+ /*0c75:*/ 0x07,0xc0, /* .....#####...... */
+ /*0c77:*/ 0x07,0x80, /* .....####....... */
+ /*0c79:*/ 0x03,0x80, /* ......###....... */
+ /*0c7b:*/ 0x03,0x80, /* ......###....... */
+ /*0c7d:*/ 0x07,0x00, /* .....###........ */
+ /*0c7f:*/ 0x07,0x00, /* .....###........ */
+ /*0c81:*/ 0x0e,0x00, /* ....###......... */
+ /*0c83:*/ 0x3e,0x00, /* ..#####......... */
+ /*0c85:*/ 0x3c,0x00, /* ..####.......... */
+/* --- new character z (122) starting at offset 0x0c87 --- */
+ /*0c87:*/ 13, 11, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0c8c:*/ 0xff,0xe0, /* ###########..... */
+ /*0c8e:*/ 0xff,0xe0, /* ###########..... */
+ /*0c90:*/ 0x01,0xc0, /* .......###...... */
+ /*0c92:*/ 0x03,0x80, /* ......###....... */
+ /*0c94:*/ 0x07,0x80, /* .....####....... */
+ /*0c96:*/ 0x0f,0x00, /* ....####........ */
+ /*0c98:*/ 0x0e,0x00, /* ....###......... */
+ /*0c9a:*/ 0x1e,0x00, /* ...####......... */
+ /*0c9c:*/ 0x3c,0x00, /* ..####.......... */
+ /*0c9e:*/ 0x38,0x00, /* ..###........... */
+ /*0ca0:*/ 0x70,0x00, /* .###............ */
+ /*0ca2:*/ 0xf0,0x00, /* ####............ */
+ /*0ca4:*/ 0xff,0xe0, /* ###########..... */
+ /*0ca6:*/ 0xff,0xe0, /* ###########..... */
+/* --- new character braceleft (123) starting at offset 0x0ca8 --- */
+ /*0ca8:*/ 10, 7, 24, 1, -5, /* width and bbox (w,h,x,y) */
+ /*0cad:*/ 0x0e, /* ....###. */
+ /*0cae:*/ 0x1c, /* ...###.. */
+ /*0caf:*/ 0x38, /* ..###... */
+ /*0cb0:*/ 0x38, /* ..###... */
+ /*0cb1:*/ 0x38, /* ..###... */
+ /*0cb2:*/ 0x38, /* ..###... */
+ /*0cb3:*/ 0x38, /* ..###... */
+ /*0cb4:*/ 0x38, /* ..###... */
+ /*0cb5:*/ 0x38, /* ..###... */
+ /*0cb6:*/ 0x38, /* ..###... */
+ /*0cb7:*/ 0x70, /* .###.... */
+ /*0cb8:*/ 0xe0, /* ###..... */
+ /*0cb9:*/ 0xe0, /* ###..... */
+ /*0cba:*/ 0x70, /* .###.... */
+ /*0cbb:*/ 0x38, /* ..###... */
+ /*0cbc:*/ 0x38, /* ..###... */
+ /*0cbd:*/ 0x38, /* ..###... */
+ /*0cbe:*/ 0x38, /* ..###... */
+ /*0cbf:*/ 0x38, /* ..###... */
+ /*0cc0:*/ 0x38, /* ..###... */
+ /*0cc1:*/ 0x38, /* ..###... */
+ /*0cc2:*/ 0x38, /* ..###... */
+ /*0cc3:*/ 0x1c, /* ...###.. */
+ /*0cc4:*/ 0x0e, /* ....###. */
+/* --- new character bar (124) starting at offset 0x0cc5 --- */
+ /*0cc5:*/ 7, 3, 24, 2, -5, /* width and bbox (w,h,x,y) */
+ /*0cca:*/ 0xe0, /* ###..... */
+ /*0ccb:*/ 0xe0, /* ###..... */
+ /*0ccc:*/ 0xe0, /* ###..... */
+ /*0ccd:*/ 0xe0, /* ###..... */
+ /*0cce:*/ 0xe0, /* ###..... */
+ /*0ccf:*/ 0xe0, /* ###..... */
+ /*0cd0:*/ 0xe0, /* ###..... */
+ /*0cd1:*/ 0xe0, /* ###..... */
+ /*0cd2:*/ 0xe0, /* ###..... */
+ /*0cd3:*/ 0xe0, /* ###..... */
+ /*0cd4:*/ 0xe0, /* ###..... */
+ /*0cd5:*/ 0xe0, /* ###..... */
+ /*0cd6:*/ 0xe0, /* ###..... */
+ /*0cd7:*/ 0xe0, /* ###..... */
+ /*0cd8:*/ 0xe0, /* ###..... */
+ /*0cd9:*/ 0xe0, /* ###..... */
+ /*0cda:*/ 0xe0, /* ###..... */
+ /*0cdb:*/ 0xe0, /* ###..... */
+ /*0cdc:*/ 0xe0, /* ###..... */
+ /*0cdd:*/ 0xe0, /* ###..... */
+ /*0cde:*/ 0xe0, /* ###..... */
+ /*0cdf:*/ 0xe0, /* ###..... */
+ /*0ce0:*/ 0xe0, /* ###..... */
+ /*0ce1:*/ 0xe0, /* ###..... */
+/* --- new character braceright (125) starting at offset 0x0ce2 --- */
+ /*0ce2:*/ 10, 7, 24, 2, -5, /* width and bbox (w,h,x,y) */
+ /*0ce7:*/ 0xe0, /* ###..... */
+ /*0ce8:*/ 0x70, /* .###.... */
+ /*0ce9:*/ 0x38, /* ..###... */
+ /*0cea:*/ 0x38, /* ..###... */
+ /*0ceb:*/ 0x38, /* ..###... */
+ /*0cec:*/ 0x38, /* ..###... */
+ /*0ced:*/ 0x38, /* ..###... */
+ /*0cee:*/ 0x38, /* ..###... */
+ /*0cef:*/ 0x38, /* ..###... */
+ /*0cf0:*/ 0x38, /* ..###... */
+ /*0cf1:*/ 0x1c, /* ...###.. */
+ /*0cf2:*/ 0x0e, /* ....###. */
+ /*0cf3:*/ 0x0e, /* ....###. */
+ /*0cf4:*/ 0x1c, /* ...###.. */
+ /*0cf5:*/ 0x38, /* ..###... */
+ /*0cf6:*/ 0x38, /* ..###... */
+ /*0cf7:*/ 0x38, /* ..###... */
+ /*0cf8:*/ 0x38, /* ..###... */
+ /*0cf9:*/ 0x38, /* ..###... */
+ /*0cfa:*/ 0x38, /* ..###... */
+ /*0cfb:*/ 0x38, /* ..###... */
+ /*0cfc:*/ 0x38, /* ..###... */
+ /*0cfd:*/ 0x70, /* .###.... */
+ /*0cfe:*/ 0xe0, /* ###..... */
+/* --- new character asciitilde (126) starting at offset 0x0cff --- */
+ /*0cff:*/ 14, 11, 4, 1, 5, /* width and bbox (w,h,x,y) */
+ /*0d04:*/ 0x78,0xe0, /* .####...###..... */
+ /*0d06:*/ 0xfe,0xe0, /* #######.###..... */
+ /*0d08:*/ 0xef,0xe0, /* ###.#######..... */
+ /*0d0a:*/ 0xe3,0xc0, /* ###...####...... */
+};
+static const uint16_t font_helvB24_offsets[] = {
+0x0000 /* space */,
+ 0x0006 /* exclam */,
+ 0x001e /* quotedbl */,
+ 0x0029 /* numbersign */,
+ 0x0052 /* dollar */,
+ 0x0081 /* percent */,
+ 0x00bc /* ampersand */,
+ 0x00e5 /* quotesingle */,
+ 0x00f0 /* parenleft */,
+ 0x010d /* parenright */,
+ 0x012a /* asterisk */,
+ 0x0136 /* plus */,
+ 0x0153 /* comma */,
+ 0x015e /* hyphen */,
+ 0x0166 /* period */,
+ 0x016e /* slash */,
+ 0x0186 /* zero */,
+ 0x01af /* one */,
+ 0x01c6 /* two */,
+ 0x01ef /* three */,
+ 0x0218 /* four */,
+ 0x0241 /* five */,
+ 0x026a /* six */,
+ 0x0293 /* seven */,
+ 0x02bc /* eight */,
+ 0x02e5 /* nine */,
+ 0x030e /* colon */,
+ 0x0321 /* semicolon */,
+ 0x0337 /* less */,
+ 0x0354 /* equal */,
+ 0x0365 /* greater */,
+ 0x0382 /* question */,
+ 0x03ad /* at */,
+ 0x03f4 /* A */,
+ 0x041f /* B */,
+ 0x044a /* C */,
+ 0x0475 /* D */,
+ 0x04a0 /* E */,
+ 0x04cb /* F */,
+ 0x04f6 /* G */,
+ 0x0534 /* H */,
+ 0x055f /* I */,
+ 0x0577 /* J */,
+ 0x05a2 /* K */,
+ 0x05cd /* L */,
+ 0x05f8 /* M */,
+ 0x0636 /* N */,
+ 0x0661 /* O */,
+ 0x069f /* P */,
+ 0x06ca /* Q */,
+ 0x0708 /* R */,
+ 0x0733 /* S */,
+ 0x075e /* T */,
+ 0x0789 /* U */,
+ 0x07b4 /* V */,
+ 0x07df /* W */,
+ 0x081d /* X */,
+ 0x0848 /* Y */,
+ 0x0873 /* Z */,
+ 0x089e /* bracketleft */,
+ 0x08bb /* backslash */,
+ 0x08d3 /* bracketright */,
+ 0x08f0 /* asciicircum */,
+ 0x0907 /* underscore */,
+ 0x0910 /* grave */,
+ 0x0919 /* a */,
+ 0x093a /* b */,
+ 0x0965 /* c */,
+ 0x0986 /* d */,
+ 0x09b1 /* e */,
+ 0x09d2 /* f */,
+ 0x09ea /* g */,
+ 0x0a15 /* h */,
+ 0x0a40 /* i */,
+ 0x0a58 /* j */,
+ 0x0a75 /* k */,
+ 0x0aa0 /* l */,
+ 0x0ab8 /* m */,
+ 0x0ae7 /* n */,
+ 0x0b08 /* o */,
+ 0x0b29 /* p */,
+ 0x0b54 /* q */,
+ 0x0b7f /* r */,
+ 0x0b92 /* s */,
+ 0x0bb3 /* t */,
+ 0x0bca /* u */,
+ 0x0beb /* v */,
+ 0x0c0c /* w */,
+ 0x0c3b /* x */,
+ 0x0c5c /* y */,
+ 0x0c87 /* z */,
+ 0x0ca8 /* braceleft */,
+ 0x0cc5 /* bar */,
+ 0x0ce2 /* braceright */,
+ 0x0cff /* asciitilde */,
+ 0xffff /* (no glyph) */
+};
+const struct fb_font font_helvB24 = {
+ .height = 27,
+ .ascent = 22,
+ .firstchar = 32, /* space */
+ .lastchar = 127, /* ? */
+ .chardata = font_helvB24_data,
+ .charoffs = font_helvB24_offsets,
+};
diff --git a/src/target/firmware/fb/helvR08.c b/src/target/firmware/fb/helvR08.c
new file mode 100644
index 00000000..7ebf82ea
--- /dev/null
+++ b/src/target/firmware/fb/helvR08.c
@@ -0,0 +1,826 @@
+#include <fb/font.h>
+static const uint8_t font_helvR08_data[] = {
+/* --- new character space (32) starting at offset 0x0000 --- */
+ /*0000:*/ 2, 1, 1, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x00, /* ........ */
+/* --- new character exclam (33) starting at offset 0x0006 --- */
+ /*0006:*/ 2, 1, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*000b:*/ 0x80, /* #....... */
+ /*000c:*/ 0x80, /* #....... */
+ /*000d:*/ 0x80, /* #....... */
+ /*000e:*/ 0x80, /* #....... */
+ /*000f:*/ 0x00, /* ........ */
+ /*0010:*/ 0x80, /* #....... */
+/* --- new character quotedbl (34) starting at offset 0x0011 --- */
+ /*0011:*/ 3, 3, 3, 1, 3, /* width and bbox (w,h,x,y) */
+ /*0016:*/ 0xa0, /* #.#..... */
+ /*0017:*/ 0xa0, /* #.#..... */
+ /*0018:*/ 0xa0, /* #.#..... */
+/* --- new character numbersign (35) starting at offset 0x0019 --- */
+ /*0019:*/ 5, 5, 5, 0, 0, /* width and bbox (w,h,x,y) */
+ /*001e:*/ 0x50, /* .#.#.... */
+ /*001f:*/ 0xf8, /* #####... */
+ /*0020:*/ 0x50, /* .#.#.... */
+ /*0021:*/ 0xf8, /* #####... */
+ /*0022:*/ 0x50, /* .#.#.... */
+/* --- new character dollar (36) starting at offset 0x0023 --- */
+ /*0023:*/ 5, 4, 7, 1, -1, /* width and bbox (w,h,x,y) */
+ /*0028:*/ 0x20, /* ..#..... */
+ /*0029:*/ 0x70, /* .###.... */
+ /*002a:*/ 0x80, /* #....... */
+ /*002b:*/ 0x60, /* .##..... */
+ /*002c:*/ 0x10, /* ...#.... */
+ /*002d:*/ 0xe0, /* ###..... */
+ /*002e:*/ 0x40, /* .#...... */
+/* --- new character percent (37) starting at offset 0x002f --- */
+ /*002f:*/ 7, 6, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0034:*/ 0xe8, /* ###.#... */
+ /*0035:*/ 0xa8, /* #.#.#... */
+ /*0036:*/ 0xd0, /* ##.#.... */
+ /*0037:*/ 0x2c, /* ..#.##.. */
+ /*0038:*/ 0x54, /* .#.#.#.. */
+ /*0039:*/ 0x5c, /* .#.###.. */
+/* --- new character ampersand (38) starting at offset 0x003a --- */
+ /*003a:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*003f:*/ 0x40, /* .#...... */
+ /*0040:*/ 0xa0, /* #.#..... */
+ /*0041:*/ 0x48, /* .#..#... */
+ /*0042:*/ 0xa8, /* #.#.#... */
+ /*0043:*/ 0xb0, /* #.##.... */
+ /*0044:*/ 0x58, /* .#.##... */
+/* --- new character quotesingle (39) starting at offset 0x0045 --- */
+ /*0045:*/ 2, 1, 2, 0, 6, /* width and bbox (w,h,x,y) */
+ /*004a:*/ 0x80, /* #....... */
+ /*004b:*/ 0x80, /* #....... */
+/* --- new character parenleft (40) starting at offset 0x004c --- */
+ /*004c:*/ 3, 2, 7, 1, -1, /* width and bbox (w,h,x,y) */
+ /*0051:*/ 0x40, /* .#...... */
+ /*0052:*/ 0x80, /* #....... */
+ /*0053:*/ 0x80, /* #....... */
+ /*0054:*/ 0x80, /* #....... */
+ /*0055:*/ 0x80, /* #....... */
+ /*0056:*/ 0x80, /* #....... */
+ /*0057:*/ 0x40, /* .#...... */
+/* --- new character parenright (41) starting at offset 0x0058 --- */
+ /*0058:*/ 3, 2, 7, 1, -1, /* width and bbox (w,h,x,y) */
+ /*005d:*/ 0x80, /* #....... */
+ /*005e:*/ 0x40, /* .#...... */
+ /*005f:*/ 0x40, /* .#...... */
+ /*0060:*/ 0x40, /* .#...... */
+ /*0061:*/ 0x40, /* .#...... */
+ /*0062:*/ 0x40, /* .#...... */
+ /*0063:*/ 0x80, /* #....... */
+/* --- new character asterisk (42) starting at offset 0x0064 --- */
+ /*0064:*/ 3, 3, 3, 1, 2, /* width and bbox (w,h,x,y) */
+ /*0069:*/ 0x40, /* .#...... */
+ /*006a:*/ 0xe0, /* ###..... */
+ /*006b:*/ 0x40, /* .#...... */
+/* --- new character plus (43) starting at offset 0x006c --- */
+ /*006c:*/ 5, 5, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0071:*/ 0x20, /* ..#..... */
+ /*0072:*/ 0x20, /* ..#..... */
+ /*0073:*/ 0xf8, /* #####... */
+ /*0074:*/ 0x20, /* ..#..... */
+ /*0075:*/ 0x20, /* ..#..... */
+/* --- new character comma (44) starting at offset 0x0076 --- */
+ /*0076:*/ 2, 2, 3, 0, -2, /* width and bbox (w,h,x,y) */
+ /*007b:*/ 0x40, /* .#...... */
+ /*007c:*/ 0x40, /* .#...... */
+ /*007d:*/ 0x80, /* #....... */
+/* --- new character hyphen (45) starting at offset 0x007e --- */
+ /*007e:*/ 3, 2, 1, 0, 2, /* width and bbox (w,h,x,y) */
+ /*0083:*/ 0xc0, /* ##...... */
+/* --- new character period (46) starting at offset 0x0084 --- */
+ /*0084:*/ 2, 1, 1, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0089:*/ 0x80, /* #....... */
+/* --- new character slash (47) starting at offset 0x008a --- */
+ /*008a:*/ 2, 2, 7, 1, -1, /* width and bbox (w,h,x,y) */
+ /*008f:*/ 0x40, /* .#...... */
+ /*0090:*/ 0x40, /* .#...... */
+ /*0091:*/ 0x40, /* .#...... */
+ /*0092:*/ 0x80, /* #....... */
+ /*0093:*/ 0x80, /* #....... */
+ /*0094:*/ 0x80, /* #....... */
+ /*0095:*/ 0x80, /* #....... */
+/* --- new character zero (48) starting at offset 0x0096 --- */
+ /*0096:*/ 5, 4, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*009b:*/ 0x60, /* .##..... */
+ /*009c:*/ 0x90, /* #..#.... */
+ /*009d:*/ 0x90, /* #..#.... */
+ /*009e:*/ 0x90, /* #..#.... */
+ /*009f:*/ 0x90, /* #..#.... */
+ /*00a0:*/ 0x60, /* .##..... */
+/* --- new character one (49) starting at offset 0x00a1 --- */
+ /*00a1:*/ 5, 2, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*00a6:*/ 0x40, /* .#...... */
+ /*00a7:*/ 0xc0, /* ##...... */
+ /*00a8:*/ 0x40, /* .#...... */
+ /*00a9:*/ 0x40, /* .#...... */
+ /*00aa:*/ 0x40, /* .#...... */
+ /*00ab:*/ 0x40, /* .#...... */
+/* --- new character two (50) starting at offset 0x00ac --- */
+ /*00ac:*/ 5, 4, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00b1:*/ 0x60, /* .##..... */
+ /*00b2:*/ 0x90, /* #..#.... */
+ /*00b3:*/ 0x10, /* ...#.... */
+ /*00b4:*/ 0x20, /* ..#..... */
+ /*00b5:*/ 0x40, /* .#...... */
+ /*00b6:*/ 0xf0, /* ####.... */
+/* --- new character three (51) starting at offset 0x00b7 --- */
+ /*00b7:*/ 5, 3, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*00bc:*/ 0xc0, /* ##...... */
+ /*00bd:*/ 0x20, /* ..#..... */
+ /*00be:*/ 0xc0, /* ##...... */
+ /*00bf:*/ 0x20, /* ..#..... */
+ /*00c0:*/ 0x20, /* ..#..... */
+ /*00c1:*/ 0xc0, /* ##...... */
+/* --- new character four (52) starting at offset 0x00c2 --- */
+ /*00c2:*/ 5, 4, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00c7:*/ 0x20, /* ..#..... */
+ /*00c8:*/ 0x20, /* ..#..... */
+ /*00c9:*/ 0x60, /* .##..... */
+ /*00ca:*/ 0xf0, /* ####.... */
+ /*00cb:*/ 0x20, /* ..#..... */
+ /*00cc:*/ 0x20, /* ..#..... */
+/* --- new character five (53) starting at offset 0x00cd --- */
+ /*00cd:*/ 5, 3, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*00d2:*/ 0xe0, /* ###..... */
+ /*00d3:*/ 0x80, /* #....... */
+ /*00d4:*/ 0xc0, /* ##...... */
+ /*00d5:*/ 0x20, /* ..#..... */
+ /*00d6:*/ 0x20, /* ..#..... */
+ /*00d7:*/ 0xc0, /* ##...... */
+/* --- new character six (54) starting at offset 0x00d8 --- */
+ /*00d8:*/ 5, 4, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00dd:*/ 0x70, /* .###.... */
+ /*00de:*/ 0x80, /* #....... */
+ /*00df:*/ 0xe0, /* ###..... */
+ /*00e0:*/ 0x90, /* #..#.... */
+ /*00e1:*/ 0x90, /* #..#.... */
+ /*00e2:*/ 0x60, /* .##..... */
+/* --- new character seven (55) starting at offset 0x00e3 --- */
+ /*00e3:*/ 5, 4, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00e8:*/ 0xf0, /* ####.... */
+ /*00e9:*/ 0x10, /* ...#.... */
+ /*00ea:*/ 0x20, /* ..#..... */
+ /*00eb:*/ 0x40, /* .#...... */
+ /*00ec:*/ 0x40, /* .#...... */
+ /*00ed:*/ 0x40, /* .#...... */
+/* --- new character eight (56) starting at offset 0x00ee --- */
+ /*00ee:*/ 5, 4, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00f3:*/ 0x60, /* .##..... */
+ /*00f4:*/ 0x90, /* #..#.... */
+ /*00f5:*/ 0x60, /* .##..... */
+ /*00f6:*/ 0x90, /* #..#.... */
+ /*00f7:*/ 0x90, /* #..#.... */
+ /*00f8:*/ 0x60, /* .##..... */
+/* --- new character nine (57) starting at offset 0x00f9 --- */
+ /*00f9:*/ 5, 4, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00fe:*/ 0x60, /* .##..... */
+ /*00ff:*/ 0x90, /* #..#.... */
+ /*0100:*/ 0x90, /* #..#.... */
+ /*0101:*/ 0x70, /* .###.... */
+ /*0102:*/ 0x10, /* ...#.... */
+ /*0103:*/ 0x60, /* .##..... */
+/* --- new character colon (58) starting at offset 0x0104 --- */
+ /*0104:*/ 2, 1, 4, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0109:*/ 0x80, /* #....... */
+ /*010a:*/ 0x00, /* ........ */
+ /*010b:*/ 0x00, /* ........ */
+ /*010c:*/ 0x80, /* #....... */
+/* --- new character semicolon (59) starting at offset 0x010d --- */
+ /*010d:*/ 2, 2, 6, 0, -2, /* width and bbox (w,h,x,y) */
+ /*0112:*/ 0x40, /* .#...... */
+ /*0113:*/ 0x00, /* ........ */
+ /*0114:*/ 0x00, /* ........ */
+ /*0115:*/ 0x40, /* .#...... */
+ /*0116:*/ 0x40, /* .#...... */
+ /*0117:*/ 0x80, /* #....... */
+/* --- new character less (60) starting at offset 0x0118 --- */
+ /*0118:*/ 5, 3, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*011d:*/ 0x20, /* ..#..... */
+ /*011e:*/ 0x40, /* .#...... */
+ /*011f:*/ 0x80, /* #....... */
+ /*0120:*/ 0x40, /* .#...... */
+ /*0121:*/ 0x20, /* ..#..... */
+/* --- new character equal (61) starting at offset 0x0122 --- */
+ /*0122:*/ 4, 3, 3, 1, 1, /* width and bbox (w,h,x,y) */
+ /*0127:*/ 0xe0, /* ###..... */
+ /*0128:*/ 0x00, /* ........ */
+ /*0129:*/ 0xe0, /* ###..... */
+/* --- new character greater (62) starting at offset 0x012a --- */
+ /*012a:*/ 5, 3, 5, 2, 0, /* width and bbox (w,h,x,y) */
+ /*012f:*/ 0x80, /* #....... */
+ /*0130:*/ 0x40, /* .#...... */
+ /*0131:*/ 0x20, /* ..#..... */
+ /*0132:*/ 0x40, /* .#...... */
+ /*0133:*/ 0x80, /* #....... */
+/* --- new character question (63) starting at offset 0x0134 --- */
+ /*0134:*/ 5, 3, 5, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0139:*/ 0xc0, /* ##...... */
+ /*013a:*/ 0x20, /* ..#..... */
+ /*013b:*/ 0x40, /* .#...... */
+ /*013c:*/ 0x00, /* ........ */
+ /*013d:*/ 0x40, /* .#...... */
+/* --- new character at (64) starting at offset 0x013e --- */
+ /*013e:*/ 9, 8, 7, 1, -1, /* width and bbox (w,h,x,y) */
+ /*0143:*/ 0x3e, /* ..#####. */
+ /*0144:*/ 0x41, /* .#.....# */
+ /*0145:*/ 0x99, /* #..##..# */
+ /*0146:*/ 0xa5, /* #.#..#.# */
+ /*0147:*/ 0x9e, /* #..####. */
+ /*0148:*/ 0x80, /* #....... */
+ /*0149:*/ 0x78, /* .####... */
+/* --- new character A (65) starting at offset 0x014a --- */
+ /*014a:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*014f:*/ 0x20, /* ..#..... */
+ /*0150:*/ 0x20, /* ..#..... */
+ /*0151:*/ 0x50, /* .#.#.... */
+ /*0152:*/ 0x70, /* .###.... */
+ /*0153:*/ 0x88, /* #...#... */
+ /*0154:*/ 0x88, /* #...#... */
+/* --- new character B (66) starting at offset 0x0155 --- */
+ /*0155:*/ 6, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*015a:*/ 0xe0, /* ###..... */
+ /*015b:*/ 0x90, /* #..#.... */
+ /*015c:*/ 0xe0, /* ###..... */
+ /*015d:*/ 0x90, /* #..#.... */
+ /*015e:*/ 0x90, /* #..#.... */
+ /*015f:*/ 0xe0, /* ###..... */
+/* --- new character C (67) starting at offset 0x0160 --- */
+ /*0160:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0165:*/ 0x70, /* .###.... */
+ /*0166:*/ 0x88, /* #...#... */
+ /*0167:*/ 0x80, /* #....... */
+ /*0168:*/ 0x80, /* #....... */
+ /*0169:*/ 0x88, /* #...#... */
+ /*016a:*/ 0x70, /* .###.... */
+/* --- new character D (68) starting at offset 0x016b --- */
+ /*016b:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0170:*/ 0xf0, /* ####.... */
+ /*0171:*/ 0x88, /* #...#... */
+ /*0172:*/ 0x88, /* #...#... */
+ /*0173:*/ 0x88, /* #...#... */
+ /*0174:*/ 0x88, /* #...#... */
+ /*0175:*/ 0xf0, /* ####.... */
+/* --- new character E (69) starting at offset 0x0176 --- */
+ /*0176:*/ 6, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*017b:*/ 0xf0, /* ####.... */
+ /*017c:*/ 0x80, /* #....... */
+ /*017d:*/ 0xe0, /* ###..... */
+ /*017e:*/ 0x80, /* #....... */
+ /*017f:*/ 0x80, /* #....... */
+ /*0180:*/ 0xf0, /* ####.... */
+/* --- new character F (70) starting at offset 0x0181 --- */
+ /*0181:*/ 5, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0186:*/ 0xf0, /* ####.... */
+ /*0187:*/ 0x80, /* #....... */
+ /*0188:*/ 0xe0, /* ###..... */
+ /*0189:*/ 0x80, /* #....... */
+ /*018a:*/ 0x80, /* #....... */
+ /*018b:*/ 0x80, /* #....... */
+/* --- new character G (71) starting at offset 0x018c --- */
+ /*018c:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0191:*/ 0x70, /* .###.... */
+ /*0192:*/ 0x80, /* #....... */
+ /*0193:*/ 0x98, /* #..##... */
+ /*0194:*/ 0x88, /* #...#... */
+ /*0195:*/ 0x88, /* #...#... */
+ /*0196:*/ 0x70, /* .###.... */
+/* --- new character H (72) starting at offset 0x0197 --- */
+ /*0197:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*019c:*/ 0x88, /* #...#... */
+ /*019d:*/ 0x88, /* #...#... */
+ /*019e:*/ 0xf8, /* #####... */
+ /*019f:*/ 0x88, /* #...#... */
+ /*01a0:*/ 0x88, /* #...#... */
+ /*01a1:*/ 0x88, /* #...#... */
+/* --- new character I (73) starting at offset 0x01a2 --- */
+ /*01a2:*/ 2, 1, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01a7:*/ 0x80, /* #....... */
+ /*01a8:*/ 0x80, /* #....... */
+ /*01a9:*/ 0x80, /* #....... */
+ /*01aa:*/ 0x80, /* #....... */
+ /*01ab:*/ 0x80, /* #....... */
+ /*01ac:*/ 0x80, /* #....... */
+/* --- new character J (74) starting at offset 0x01ad --- */
+ /*01ad:*/ 4, 3, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01b2:*/ 0x20, /* ..#..... */
+ /*01b3:*/ 0x20, /* ..#..... */
+ /*01b4:*/ 0x20, /* ..#..... */
+ /*01b5:*/ 0x20, /* ..#..... */
+ /*01b6:*/ 0xa0, /* #.#..... */
+ /*01b7:*/ 0x40, /* .#...... */
+/* --- new character K (75) starting at offset 0x01b8 --- */
+ /*01b8:*/ 6, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*01bd:*/ 0x90, /* #..#.... */
+ /*01be:*/ 0xa0, /* #.#..... */
+ /*01bf:*/ 0xc0, /* ##...... */
+ /*01c0:*/ 0xe0, /* ###..... */
+ /*01c1:*/ 0x90, /* #..#.... */
+ /*01c2:*/ 0x90, /* #..#.... */
+/* --- new character L (76) starting at offset 0x01c3 --- */
+ /*01c3:*/ 5, 3, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*01c8:*/ 0x80, /* #....... */
+ /*01c9:*/ 0x80, /* #....... */
+ /*01ca:*/ 0x80, /* #....... */
+ /*01cb:*/ 0x80, /* #....... */
+ /*01cc:*/ 0x80, /* #....... */
+ /*01cd:*/ 0xe0, /* ###..... */
+/* --- new character M (77) starting at offset 0x01ce --- */
+ /*01ce:*/ 7, 5, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*01d3:*/ 0x88, /* #...#... */
+ /*01d4:*/ 0xd8, /* ##.##... */
+ /*01d5:*/ 0xa8, /* #.#.#... */
+ /*01d6:*/ 0xa8, /* #.#.#... */
+ /*01d7:*/ 0xa8, /* #.#.#... */
+ /*01d8:*/ 0xa8, /* #.#.#... */
+/* --- new character N (78) starting at offset 0x01d9 --- */
+ /*01d9:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01de:*/ 0x88, /* #...#... */
+ /*01df:*/ 0xc8, /* ##..#... */
+ /*01e0:*/ 0xa8, /* #.#.#... */
+ /*01e1:*/ 0xa8, /* #.#.#... */
+ /*01e2:*/ 0x98, /* #..##... */
+ /*01e3:*/ 0x88, /* #...#... */
+/* --- new character O (79) starting at offset 0x01e4 --- */
+ /*01e4:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01e9:*/ 0x70, /* .###.... */
+ /*01ea:*/ 0x88, /* #...#... */
+ /*01eb:*/ 0x88, /* #...#... */
+ /*01ec:*/ 0x88, /* #...#... */
+ /*01ed:*/ 0x88, /* #...#... */
+ /*01ee:*/ 0x70, /* .###.... */
+/* --- new character P (80) starting at offset 0x01ef --- */
+ /*01ef:*/ 6, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*01f4:*/ 0xe0, /* ###..... */
+ /*01f5:*/ 0x90, /* #..#.... */
+ /*01f6:*/ 0x90, /* #..#.... */
+ /*01f7:*/ 0xe0, /* ###..... */
+ /*01f8:*/ 0x80, /* #....... */
+ /*01f9:*/ 0x80, /* #....... */
+/* --- new character Q (81) starting at offset 0x01fa --- */
+ /*01fa:*/ 6, 5, 8, 1, -2, /* width and bbox (w,h,x,y) */
+ /*01ff:*/ 0x70, /* .###.... */
+ /*0200:*/ 0x88, /* #...#... */
+ /*0201:*/ 0x88, /* #...#... */
+ /*0202:*/ 0x88, /* #...#... */
+ /*0203:*/ 0x88, /* #...#... */
+ /*0204:*/ 0x70, /* .###.... */
+ /*0205:*/ 0x20, /* ..#..... */
+ /*0206:*/ 0x10, /* ...#.... */
+/* --- new character R (82) starting at offset 0x0207 --- */
+ /*0207:*/ 6, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*020c:*/ 0xe0, /* ###..... */
+ /*020d:*/ 0x90, /* #..#.... */
+ /*020e:*/ 0x90, /* #..#.... */
+ /*020f:*/ 0xe0, /* ###..... */
+ /*0210:*/ 0x90, /* #..#.... */
+ /*0211:*/ 0x90, /* #..#.... */
+/* --- new character S (83) starting at offset 0x0212 --- */
+ /*0212:*/ 6, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0217:*/ 0x70, /* .###.... */
+ /*0218:*/ 0x80, /* #....... */
+ /*0219:*/ 0xe0, /* ###..... */
+ /*021a:*/ 0x10, /* ...#.... */
+ /*021b:*/ 0x10, /* ...#.... */
+ /*021c:*/ 0xe0, /* ###..... */
+/* --- new character T (84) starting at offset 0x021d --- */
+ /*021d:*/ 4, 3, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0222:*/ 0xe0, /* ###..... */
+ /*0223:*/ 0x40, /* .#...... */
+ /*0224:*/ 0x40, /* .#...... */
+ /*0225:*/ 0x40, /* .#...... */
+ /*0226:*/ 0x40, /* .#...... */
+ /*0227:*/ 0x40, /* .#...... */
+/* --- new character U (85) starting at offset 0x0228 --- */
+ /*0228:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*022d:*/ 0x88, /* #...#... */
+ /*022e:*/ 0x88, /* #...#... */
+ /*022f:*/ 0x88, /* #...#... */
+ /*0230:*/ 0x88, /* #...#... */
+ /*0231:*/ 0x88, /* #...#... */
+ /*0232:*/ 0x70, /* .###.... */
+/* --- new character V (86) starting at offset 0x0233 --- */
+ /*0233:*/ 6, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0238:*/ 0x90, /* #..#.... */
+ /*0239:*/ 0x90, /* #..#.... */
+ /*023a:*/ 0x90, /* #..#.... */
+ /*023b:*/ 0x90, /* #..#.... */
+ /*023c:*/ 0xa0, /* #.#..... */
+ /*023d:*/ 0x40, /* .#...... */
+/* --- new character W (87) starting at offset 0x023e --- */
+ /*023e:*/ 7, 7, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0243:*/ 0x92, /* #..#..#. */
+ /*0244:*/ 0x92, /* #..#..#. */
+ /*0245:*/ 0x92, /* #..#..#. */
+ /*0246:*/ 0x6c, /* .##.##.. */
+ /*0247:*/ 0x48, /* .#..#... */
+ /*0248:*/ 0x48, /* .#..#... */
+/* --- new character X (88) starting at offset 0x0249 --- */
+ /*0249:*/ 6, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*024e:*/ 0x90, /* #..#.... */
+ /*024f:*/ 0x90, /* #..#.... */
+ /*0250:*/ 0x60, /* .##..... */
+ /*0251:*/ 0x60, /* .##..... */
+ /*0252:*/ 0x90, /* #..#.... */
+ /*0253:*/ 0x90, /* #..#.... */
+/* --- new character Y (89) starting at offset 0x0254 --- */
+ /*0254:*/ 6, 5, 6, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0259:*/ 0xc8, /* ##..#... */
+ /*025a:*/ 0x48, /* .#..#... */
+ /*025b:*/ 0x48, /* .#..#... */
+ /*025c:*/ 0x30, /* ..##.... */
+ /*025d:*/ 0x20, /* ..#..... */
+ /*025e:*/ 0x20, /* ..#..... */
+/* --- new character Z (90) starting at offset 0x025f --- */
+ /*025f:*/ 6, 4, 6, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0264:*/ 0xf0, /* ####.... */
+ /*0265:*/ 0x10, /* ...#.... */
+ /*0266:*/ 0x20, /* ..#..... */
+ /*0267:*/ 0x40, /* .#...... */
+ /*0268:*/ 0x80, /* #....... */
+ /*0269:*/ 0xf0, /* ####.... */
+/* --- new character bracketleft (91) starting at offset 0x026a --- */
+ /*026a:*/ 2, 2, 7, 1, -1, /* width and bbox (w,h,x,y) */
+ /*026f:*/ 0xc0, /* ##...... */
+ /*0270:*/ 0x80, /* #....... */
+ /*0271:*/ 0x80, /* #....... */
+ /*0272:*/ 0x80, /* #....... */
+ /*0273:*/ 0x80, /* #....... */
+ /*0274:*/ 0x80, /* #....... */
+ /*0275:*/ 0xc0, /* ##...... */
+/* --- new character backslash (92) starting at offset 0x0276 --- */
+ /*0276:*/ 2, 2, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*027b:*/ 0x80, /* #....... */
+ /*027c:*/ 0x80, /* #....... */
+ /*027d:*/ 0x80, /* #....... */
+ /*027e:*/ 0x40, /* .#...... */
+ /*027f:*/ 0x40, /* .#...... */
+ /*0280:*/ 0x40, /* .#...... */
+ /*0281:*/ 0x40, /* .#...... */
+/* --- new character bracketright (93) starting at offset 0x0282 --- */
+ /*0282:*/ 2, 2, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*0287:*/ 0xc0, /* ##...... */
+ /*0288:*/ 0x40, /* .#...... */
+ /*0289:*/ 0x40, /* .#...... */
+ /*028a:*/ 0x40, /* .#...... */
+ /*028b:*/ 0x40, /* .#...... */
+ /*028c:*/ 0x40, /* .#...... */
+ /*028d:*/ 0xc0, /* ##...... */
+/* --- new character asciicircum (94) starting at offset 0x028e --- */
+ /*028e:*/ 5, 5, 3, 0, 2, /* width and bbox (w,h,x,y) */
+ /*0293:*/ 0x20, /* ..#..... */
+ /*0294:*/ 0x50, /* .#.#.... */
+ /*0295:*/ 0x88, /* #...#... */
+/* --- new character underscore (95) starting at offset 0x0296 --- */
+ /*0296:*/ 5, 5, 1, 0, -1, /* width and bbox (w,h,x,y) */
+ /*029b:*/ 0xf8, /* #####... */
+/* --- new character grave (96) starting at offset 0x029c --- */
+ /*029c:*/ 3, 2, 2, 0, 6, /* width and bbox (w,h,x,y) */
+ /*02a1:*/ 0x80, /* #....... */
+ /*02a2:*/ 0x40, /* .#...... */
+/* --- new character a (97) starting at offset 0x02a3 --- */
+ /*02a3:*/ 4, 4, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02a8:*/ 0xc0, /* ##...... */
+ /*02a9:*/ 0x20, /* ..#..... */
+ /*02aa:*/ 0xe0, /* ###..... */
+ /*02ab:*/ 0xa0, /* #.#..... */
+ /*02ac:*/ 0xd0, /* ##.#.... */
+/* --- new character b (98) starting at offset 0x02ad --- */
+ /*02ad:*/ 5, 4, 7, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02b2:*/ 0x80, /* #....... */
+ /*02b3:*/ 0x80, /* #....... */
+ /*02b4:*/ 0xe0, /* ###..... */
+ /*02b5:*/ 0x90, /* #..#.... */
+ /*02b6:*/ 0x90, /* #..#.... */
+ /*02b7:*/ 0x90, /* #..#.... */
+ /*02b8:*/ 0xe0, /* ###..... */
+/* --- new character c (99) starting at offset 0x02b9 --- */
+ /*02b9:*/ 4, 3, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02be:*/ 0x60, /* .##..... */
+ /*02bf:*/ 0x80, /* #....... */
+ /*02c0:*/ 0x80, /* #....... */
+ /*02c1:*/ 0x80, /* #....... */
+ /*02c2:*/ 0x60, /* .##..... */
+/* --- new character d (100) starting at offset 0x02c3 --- */
+ /*02c3:*/ 5, 4, 7, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02c8:*/ 0x10, /* ...#.... */
+ /*02c9:*/ 0x10, /* ...#.... */
+ /*02ca:*/ 0x70, /* .###.... */
+ /*02cb:*/ 0x90, /* #..#.... */
+ /*02cc:*/ 0x90, /* #..#.... */
+ /*02cd:*/ 0x90, /* #..#.... */
+ /*02ce:*/ 0x70, /* .###.... */
+/* --- new character e (101) starting at offset 0x02cf --- */
+ /*02cf:*/ 4, 3, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02d4:*/ 0x40, /* .#...... */
+ /*02d5:*/ 0xa0, /* #.#..... */
+ /*02d6:*/ 0xe0, /* ###..... */
+ /*02d7:*/ 0x80, /* #....... */
+ /*02d8:*/ 0x60, /* .##..... */
+/* --- new character f (102) starting at offset 0x02d9 --- */
+ /*02d9:*/ 4, 3, 7, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02de:*/ 0x20, /* ..#..... */
+ /*02df:*/ 0x40, /* .#...... */
+ /*02e0:*/ 0xe0, /* ###..... */
+ /*02e1:*/ 0x40, /* .#...... */
+ /*02e2:*/ 0x40, /* .#...... */
+ /*02e3:*/ 0x40, /* .#...... */
+ /*02e4:*/ 0x40, /* .#...... */
+/* --- new character g (103) starting at offset 0x02e5 --- */
+ /*02e5:*/ 5, 4, 6, 1, -1, /* width and bbox (w,h,x,y) */
+ /*02ea:*/ 0x70, /* .###.... */
+ /*02eb:*/ 0x90, /* #..#.... */
+ /*02ec:*/ 0x90, /* #..#.... */
+ /*02ed:*/ 0x70, /* .###.... */
+ /*02ee:*/ 0x10, /* ...#.... */
+ /*02ef:*/ 0x60, /* .##..... */
+/* --- new character h (104) starting at offset 0x02f0 --- */
+ /*02f0:*/ 5, 4, 7, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02f5:*/ 0x80, /* #....... */
+ /*02f6:*/ 0x80, /* #....... */
+ /*02f7:*/ 0xe0, /* ###..... */
+ /*02f8:*/ 0x90, /* #..#.... */
+ /*02f9:*/ 0x90, /* #..#.... */
+ /*02fa:*/ 0x90, /* #..#.... */
+ /*02fb:*/ 0x90, /* #..#.... */
+/* --- new character i (105) starting at offset 0x02fc --- */
+ /*02fc:*/ 2, 1, 7, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0301:*/ 0x80, /* #....... */
+ /*0302:*/ 0x00, /* ........ */
+ /*0303:*/ 0x80, /* #....... */
+ /*0304:*/ 0x80, /* #....... */
+ /*0305:*/ 0x80, /* #....... */
+ /*0306:*/ 0x80, /* #....... */
+ /*0307:*/ 0x80, /* #....... */
+/* --- new character j (106) starting at offset 0x0308 --- */
+ /*0308:*/ 2, 2, 9, 0, -2, /* width and bbox (w,h,x,y) */
+ /*030d:*/ 0x40, /* .#...... */
+ /*030e:*/ 0x00, /* ........ */
+ /*030f:*/ 0x40, /* .#...... */
+ /*0310:*/ 0x40, /* .#...... */
+ /*0311:*/ 0x40, /* .#...... */
+ /*0312:*/ 0x40, /* .#...... */
+ /*0313:*/ 0x40, /* .#...... */
+ /*0314:*/ 0x40, /* .#...... */
+ /*0315:*/ 0x80, /* #....... */
+/* --- new character k (107) starting at offset 0x0316 --- */
+ /*0316:*/ 4, 3, 7, 1, 0, /* width and bbox (w,h,x,y) */
+ /*031b:*/ 0x80, /* #....... */
+ /*031c:*/ 0x80, /* #....... */
+ /*031d:*/ 0xa0, /* #.#..... */
+ /*031e:*/ 0xc0, /* ##...... */
+ /*031f:*/ 0xc0, /* ##...... */
+ /*0320:*/ 0xa0, /* #.#..... */
+ /*0321:*/ 0xa0, /* #.#..... */
+/* --- new character l (108) starting at offset 0x0322 --- */
+ /*0322:*/ 2, 1, 7, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0327:*/ 0x80, /* #....... */
+ /*0328:*/ 0x80, /* #....... */
+ /*0329:*/ 0x80, /* #....... */
+ /*032a:*/ 0x80, /* #....... */
+ /*032b:*/ 0x80, /* #....... */
+ /*032c:*/ 0x80, /* #....... */
+ /*032d:*/ 0x80, /* #....... */
+/* --- new character m (109) starting at offset 0x032e --- */
+ /*032e:*/ 6, 5, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0333:*/ 0xf0, /* ####.... */
+ /*0334:*/ 0xa8, /* #.#.#... */
+ /*0335:*/ 0xa8, /* #.#.#... */
+ /*0336:*/ 0xa8, /* #.#.#... */
+ /*0337:*/ 0xa8, /* #.#.#... */
+/* --- new character n (110) starting at offset 0x0338 --- */
+ /*0338:*/ 5, 4, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*033d:*/ 0xe0, /* ###..... */
+ /*033e:*/ 0x90, /* #..#.... */
+ /*033f:*/ 0x90, /* #..#.... */
+ /*0340:*/ 0x90, /* #..#.... */
+ /*0341:*/ 0x90, /* #..#.... */
+/* --- new character o (111) starting at offset 0x0342 --- */
+ /*0342:*/ 5, 4, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0347:*/ 0x60, /* .##..... */
+ /*0348:*/ 0x90, /* #..#.... */
+ /*0349:*/ 0x90, /* #..#.... */
+ /*034a:*/ 0x90, /* #..#.... */
+ /*034b:*/ 0x60, /* .##..... */
+/* --- new character p (112) starting at offset 0x034c --- */
+ /*034c:*/ 5, 4, 6, 1, -1, /* width and bbox (w,h,x,y) */
+ /*0351:*/ 0xe0, /* ###..... */
+ /*0352:*/ 0x90, /* #..#.... */
+ /*0353:*/ 0x90, /* #..#.... */
+ /*0354:*/ 0x90, /* #..#.... */
+ /*0355:*/ 0xe0, /* ###..... */
+ /*0356:*/ 0x80, /* #....... */
+/* --- new character q (113) starting at offset 0x0357 --- */
+ /*0357:*/ 5, 4, 6, 1, -1, /* width and bbox (w,h,x,y) */
+ /*035c:*/ 0x70, /* .###.... */
+ /*035d:*/ 0x90, /* #..#.... */
+ /*035e:*/ 0x90, /* #..#.... */
+ /*035f:*/ 0x90, /* #..#.... */
+ /*0360:*/ 0x70, /* .###.... */
+ /*0361:*/ 0x10, /* ...#.... */
+/* --- new character r (114) starting at offset 0x0362 --- */
+ /*0362:*/ 3, 3, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0367:*/ 0xa0, /* #.#..... */
+ /*0368:*/ 0xc0, /* ##...... */
+ /*0369:*/ 0x80, /* #....... */
+ /*036a:*/ 0x80, /* #....... */
+ /*036b:*/ 0x80, /* #....... */
+/* --- new character s (115) starting at offset 0x036c --- */
+ /*036c:*/ 4, 3, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0371:*/ 0x60, /* .##..... */
+ /*0372:*/ 0x80, /* #....... */
+ /*0373:*/ 0x60, /* .##..... */
+ /*0374:*/ 0x20, /* ..#..... */
+ /*0375:*/ 0xc0, /* ##...... */
+/* --- new character t (116) starting at offset 0x0376 --- */
+ /*0376:*/ 3, 3, 7, 1, 0, /* width and bbox (w,h,x,y) */
+ /*037b:*/ 0x40, /* .#...... */
+ /*037c:*/ 0x40, /* .#...... */
+ /*037d:*/ 0xe0, /* ###..... */
+ /*037e:*/ 0x40, /* .#...... */
+ /*037f:*/ 0x40, /* .#...... */
+ /*0380:*/ 0x40, /* .#...... */
+ /*0381:*/ 0x40, /* .#...... */
+/* --- new character u (117) starting at offset 0x0382 --- */
+ /*0382:*/ 4, 3, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0387:*/ 0xa0, /* #.#..... */
+ /*0388:*/ 0xa0, /* #.#..... */
+ /*0389:*/ 0xa0, /* #.#..... */
+ /*038a:*/ 0xa0, /* #.#..... */
+ /*038b:*/ 0x60, /* .##..... */
+/* --- new character v (118) starting at offset 0x038c --- */
+ /*038c:*/ 5, 4, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0391:*/ 0x90, /* #..#.... */
+ /*0392:*/ 0x90, /* #..#.... */
+ /*0393:*/ 0x90, /* #..#.... */
+ /*0394:*/ 0xa0, /* #.#..... */
+ /*0395:*/ 0x40, /* .#...... */
+/* --- new character w (119) starting at offset 0x0396 --- */
+ /*0396:*/ 6, 5, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*039b:*/ 0xa8, /* #.#.#... */
+ /*039c:*/ 0xa8, /* #.#.#... */
+ /*039d:*/ 0xa8, /* #.#.#... */
+ /*039e:*/ 0x50, /* .#.#.... */
+ /*039f:*/ 0x50, /* .#.#.... */
+/* --- new character x (120) starting at offset 0x03a0 --- */
+ /*03a0:*/ 5, 4, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*03a5:*/ 0x90, /* #..#.... */
+ /*03a6:*/ 0x90, /* #..#.... */
+ /*03a7:*/ 0x60, /* .##..... */
+ /*03a8:*/ 0x90, /* #..#.... */
+ /*03a9:*/ 0x90, /* #..#.... */
+/* --- new character y (121) starting at offset 0x03aa --- */
+ /*03aa:*/ 4, 4, 6, 1, -1, /* width and bbox (w,h,x,y) */
+ /*03af:*/ 0x90, /* #..#.... */
+ /*03b0:*/ 0x90, /* #..#.... */
+ /*03b1:*/ 0x90, /* #..#.... */
+ /*03b2:*/ 0x60, /* .##..... */
+ /*03b3:*/ 0x40, /* .#...... */
+ /*03b4:*/ 0x80, /* #....... */
+/* --- new character z (122) starting at offset 0x03b5 --- */
+ /*03b5:*/ 4, 3, 5, 1, 0, /* width and bbox (w,h,x,y) */
+ /*03ba:*/ 0xe0, /* ###..... */
+ /*03bb:*/ 0x20, /* ..#..... */
+ /*03bc:*/ 0x40, /* .#...... */
+ /*03bd:*/ 0x80, /* #....... */
+ /*03be:*/ 0xe0, /* ###..... */
+/* --- new character braceleft (123) starting at offset 0x03bf --- */
+ /*03bf:*/ 2, 3, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*03c4:*/ 0x20, /* ..#..... */
+ /*03c5:*/ 0x40, /* .#...... */
+ /*03c6:*/ 0x40, /* .#...... */
+ /*03c7:*/ 0xc0, /* ##...... */
+ /*03c8:*/ 0x40, /* .#...... */
+ /*03c9:*/ 0x40, /* .#...... */
+ /*03ca:*/ 0x20, /* ..#..... */
+/* --- new character bar (124) starting at offset 0x03cb --- */
+ /*03cb:*/ 2, 1, 7, 1, -1, /* width and bbox (w,h,x,y) */
+ /*03d0:*/ 0x80, /* #....... */
+ /*03d1:*/ 0x80, /* #....... */
+ /*03d2:*/ 0x80, /* #....... */
+ /*03d3:*/ 0x80, /* #....... */
+ /*03d4:*/ 0x80, /* #....... */
+ /*03d5:*/ 0x80, /* #....... */
+ /*03d6:*/ 0x80, /* #....... */
+/* --- new character braceright (125) starting at offset 0x03d7 --- */
+ /*03d7:*/ 2, 3, 7, 0, -1, /* width and bbox (w,h,x,y) */
+ /*03dc:*/ 0x80, /* #....... */
+ /*03dd:*/ 0x40, /* .#...... */
+ /*03de:*/ 0x40, /* .#...... */
+ /*03df:*/ 0x60, /* .##..... */
+ /*03e0:*/ 0x40, /* .#...... */
+ /*03e1:*/ 0x40, /* .#...... */
+ /*03e2:*/ 0x80, /* #....... */
+/* --- new character asciitilde (126) starting at offset 0x03e3 --- */
+ /*03e3:*/ 6, 5, 2, 1, 2, /* width and bbox (w,h,x,y) */
+ /*03e8:*/ 0x48, /* .#..#... */
+ /*03e9:*/ 0xb0, /* #.##.... */
+};
+static const uint16_t font_helvR08_offsets[] = {
+0x0000 /* space */,
+ 0x0006 /* exclam */,
+ 0x0011 /* quotedbl */,
+ 0x0019 /* numbersign */,
+ 0x0023 /* dollar */,
+ 0x002f /* percent */,
+ 0x003a /* ampersand */,
+ 0x0045 /* quotesingle */,
+ 0x004c /* parenleft */,
+ 0x0058 /* parenright */,
+ 0x0064 /* asterisk */,
+ 0x006c /* plus */,
+ 0x0076 /* comma */,
+ 0x007e /* hyphen */,
+ 0x0084 /* period */,
+ 0x008a /* slash */,
+ 0x0096 /* zero */,
+ 0x00a1 /* one */,
+ 0x00ac /* two */,
+ 0x00b7 /* three */,
+ 0x00c2 /* four */,
+ 0x00cd /* five */,
+ 0x00d8 /* six */,
+ 0x00e3 /* seven */,
+ 0x00ee /* eight */,
+ 0x00f9 /* nine */,
+ 0x0104 /* colon */,
+ 0x010d /* semicolon */,
+ 0x0118 /* less */,
+ 0x0122 /* equal */,
+ 0x012a /* greater */,
+ 0x0134 /* question */,
+ 0x013e /* at */,
+ 0x014a /* A */,
+ 0x0155 /* B */,
+ 0x0160 /* C */,
+ 0x016b /* D */,
+ 0x0176 /* E */,
+ 0x0181 /* F */,
+ 0x018c /* G */,
+ 0x0197 /* H */,
+ 0x01a2 /* I */,
+ 0x01ad /* J */,
+ 0x01b8 /* K */,
+ 0x01c3 /* L */,
+ 0x01ce /* M */,
+ 0x01d9 /* N */,
+ 0x01e4 /* O */,
+ 0x01ef /* P */,
+ 0x01fa /* Q */,
+ 0x0207 /* R */,
+ 0x0212 /* S */,
+ 0x021d /* T */,
+ 0x0228 /* U */,
+ 0x0233 /* V */,
+ 0x023e /* W */,
+ 0x0249 /* X */,
+ 0x0254 /* Y */,
+ 0x025f /* Z */,
+ 0x026a /* bracketleft */,
+ 0x0276 /* backslash */,
+ 0x0282 /* bracketright */,
+ 0x028e /* asciicircum */,
+ 0x0296 /* underscore */,
+ 0x029c /* grave */,
+ 0x02a3 /* a */,
+ 0x02ad /* b */,
+ 0x02b9 /* c */,
+ 0x02c3 /* d */,
+ 0x02cf /* e */,
+ 0x02d9 /* f */,
+ 0x02e5 /* g */,
+ 0x02f0 /* h */,
+ 0x02fc /* i */,
+ 0x0308 /* j */,
+ 0x0316 /* k */,
+ 0x0322 /* l */,
+ 0x032e /* m */,
+ 0x0338 /* n */,
+ 0x0342 /* o */,
+ 0x034c /* p */,
+ 0x0357 /* q */,
+ 0x0362 /* r */,
+ 0x036c /* s */,
+ 0x0376 /* t */,
+ 0x0382 /* u */,
+ 0x038c /* v */,
+ 0x0396 /* w */,
+ 0x03a0 /* x */,
+ 0x03aa /* y */,
+ 0x03b5 /* z */,
+ 0x03bf /* braceleft */,
+ 0x03cb /* bar */,
+ 0x03d7 /* braceright */,
+ 0x03e3 /* asciitilde */,
+ 0xffff /* (no glyph) */
+};
+const struct fb_font font_helvR08 = {
+ .height = 10,
+ .ascent = 8,
+ .firstchar = 32, /* space */
+ .lastchar = 127, /* ? */
+ .chardata = font_helvR08_data,
+ .charoffs = font_helvR08_offsets,
+};
diff --git a/src/target/firmware/fb/helvR14.c b/src/target/firmware/fb/helvR14.c
new file mode 100644
index 00000000..b0281258
--- /dev/null
+++ b/src/target/firmware/fb/helvR14.c
@@ -0,0 +1,1198 @@
+#include <fb/font.h>
+static const uint8_t font_helvR14_data[] = {
+/* --- new character space (32) starting at offset 0x0000 --- */
+ /*0000:*/ 4, 1, 1, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x00, /* ........ */
+/* --- new character exclam (33) starting at offset 0x0006 --- */
+ /*0006:*/ 4, 1, 11, 2, 0, /* width and bbox (w,h,x,y) */
+ /*000b:*/ 0x80, /* #....... */
+ /*000c:*/ 0x80, /* #....... */
+ /*000d:*/ 0x80, /* #....... */
+ /*000e:*/ 0x80, /* #....... */
+ /*000f:*/ 0x80, /* #....... */
+ /*0010:*/ 0x80, /* #....... */
+ /*0011:*/ 0x80, /* #....... */
+ /*0012:*/ 0x80, /* #....... */
+ /*0013:*/ 0x00, /* ........ */
+ /*0014:*/ 0x80, /* #....... */
+ /*0015:*/ 0x80, /* #....... */
+/* --- new character quotedbl (34) starting at offset 0x0016 --- */
+ /*0016:*/ 5, 3, 3, 1, 8, /* width and bbox (w,h,x,y) */
+ /*001b:*/ 0xa0, /* #.#..... */
+ /*001c:*/ 0xa0, /* #.#..... */
+ /*001d:*/ 0xa0, /* #.#..... */
+/* --- new character numbersign (35) starting at offset 0x001e --- */
+ /*001e:*/ 8, 7, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0023:*/ 0x14, /* ...#.#.. */
+ /*0024:*/ 0x14, /* ...#.#.. */
+ /*0025:*/ 0x14, /* ...#.#.. */
+ /*0026:*/ 0x7e, /* .######. */
+ /*0027:*/ 0x28, /* ..#.#... */
+ /*0028:*/ 0x28, /* ..#.#... */
+ /*0029:*/ 0xfc, /* ######.. */
+ /*002a:*/ 0x50, /* .#.#.... */
+ /*002b:*/ 0x50, /* .#.#.... */
+ /*002c:*/ 0x50, /* .#.#.... */
+/* --- new character dollar (36) starting at offset 0x002d --- */
+ /*002d:*/ 8, 7, 14, 0, -2, /* width and bbox (w,h,x,y) */
+ /*0032:*/ 0x10, /* ...#.... */
+ /*0033:*/ 0x10, /* ...#.... */
+ /*0034:*/ 0x7c, /* .#####.. */
+ /*0035:*/ 0x92, /* #..#..#. */
+ /*0036:*/ 0x92, /* #..#..#. */
+ /*0037:*/ 0x50, /* .#.#.... */
+ /*0038:*/ 0x38, /* ..###... */
+ /*0039:*/ 0x14, /* ...#.#.. */
+ /*003a:*/ 0x12, /* ...#..#. */
+ /*003b:*/ 0x92, /* #..#..#. */
+ /*003c:*/ 0x92, /* #..#..#. */
+ /*003d:*/ 0x7c, /* .#####.. */
+ /*003e:*/ 0x10, /* ...#.... */
+ /*003f:*/ 0x10, /* ...#.... */
+/* --- new character percent (37) starting at offset 0x0040 --- */
+ /*0040:*/ 12, 11, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0045:*/ 0x70,0x80, /* .###....#....... */
+ /*0047:*/ 0x89,0x00, /* #...#..#........ */
+ /*0049:*/ 0x89,0x00, /* #...#..#........ */
+ /*004b:*/ 0x72,0x00, /* .###..#......... */
+ /*004d:*/ 0x02,0x00, /* ......#......... */
+ /*004f:*/ 0x04,0x00, /* .....#.......... */
+ /*0051:*/ 0x09,0xc0, /* ....#..###...... */
+ /*0053:*/ 0x12,0x20, /* ...#..#...#..... */
+ /*0055:*/ 0x12,0x20, /* ...#..#...#..... */
+ /*0057:*/ 0x21,0xc0, /* ..#....###...... */
+/* --- new character ampersand (38) starting at offset 0x0059 --- */
+ /*0059:*/ 10, 8, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*005e:*/ 0x30, /* ..##.... */
+ /*005f:*/ 0x48, /* .#..#... */
+ /*0060:*/ 0x48, /* .#..#... */
+ /*0061:*/ 0x30, /* ..##.... */
+ /*0062:*/ 0x20, /* ..#..... */
+ /*0063:*/ 0x52, /* .#.#..#. */
+ /*0064:*/ 0x8a, /* #...#.#. */
+ /*0065:*/ 0x84, /* #....#.. */
+ /*0066:*/ 0x8a, /* #...#.#. */
+ /*0067:*/ 0x71, /* .###...# */
+/* --- new character quotesingle (39) starting at offset 0x0068 --- */
+ /*0068:*/ 3, 1, 3, 1, 8, /* width and bbox (w,h,x,y) */
+ /*006d:*/ 0x80, /* #....... */
+ /*006e:*/ 0x80, /* #....... */
+ /*006f:*/ 0x80, /* #....... */
+/* --- new character parenleft (40) starting at offset 0x0070 --- */
+ /*0070:*/ 5, 3, 14, 1, -3, /* width and bbox (w,h,x,y) */
+ /*0075:*/ 0x20, /* ..#..... */
+ /*0076:*/ 0x40, /* .#...... */
+ /*0077:*/ 0x40, /* .#...... */
+ /*0078:*/ 0x80, /* #....... */
+ /*0079:*/ 0x80, /* #....... */
+ /*007a:*/ 0x80, /* #....... */
+ /*007b:*/ 0x80, /* #....... */
+ /*007c:*/ 0x80, /* #....... */
+ /*007d:*/ 0x80, /* #....... */
+ /*007e:*/ 0x80, /* #....... */
+ /*007f:*/ 0x80, /* #....... */
+ /*0080:*/ 0x40, /* .#...... */
+ /*0081:*/ 0x40, /* .#...... */
+ /*0082:*/ 0x20, /* ..#..... */
+/* --- new character parenright (41) starting at offset 0x0083 --- */
+ /*0083:*/ 5, 3, 14, 1, -3, /* width and bbox (w,h,x,y) */
+ /*0088:*/ 0x80, /* #....... */
+ /*0089:*/ 0x40, /* .#...... */
+ /*008a:*/ 0x40, /* .#...... */
+ /*008b:*/ 0x20, /* ..#..... */
+ /*008c:*/ 0x20, /* ..#..... */
+ /*008d:*/ 0x20, /* ..#..... */
+ /*008e:*/ 0x20, /* ..#..... */
+ /*008f:*/ 0x20, /* ..#..... */
+ /*0090:*/ 0x20, /* ..#..... */
+ /*0091:*/ 0x20, /* ..#..... */
+ /*0092:*/ 0x20, /* ..#..... */
+ /*0093:*/ 0x40, /* .#...... */
+ /*0094:*/ 0x40, /* .#...... */
+ /*0095:*/ 0x80, /* #....... */
+/* --- new character asterisk (42) starting at offset 0x0096 --- */
+ /*0096:*/ 7, 5, 4, 1, 6, /* width and bbox (w,h,x,y) */
+ /*009b:*/ 0x20, /* ..#..... */
+ /*009c:*/ 0xf8, /* #####... */
+ /*009d:*/ 0x20, /* ..#..... */
+ /*009e:*/ 0x50, /* .#.#.... */
+/* --- new character plus (43) starting at offset 0x009f --- */
+ /*009f:*/ 9, 7, 7, 1, 1, /* width and bbox (w,h,x,y) */
+ /*00a4:*/ 0x10, /* ...#.... */
+ /*00a5:*/ 0x10, /* ...#.... */
+ /*00a6:*/ 0x10, /* ...#.... */
+ /*00a7:*/ 0xfe, /* #######. */
+ /*00a8:*/ 0x10, /* ...#.... */
+ /*00a9:*/ 0x10, /* ...#.... */
+ /*00aa:*/ 0x10, /* ...#.... */
+/* --- new character comma (44) starting at offset 0x00ab --- */
+ /*00ab:*/ 3, 2, 4, 0, -2, /* width and bbox (w,h,x,y) */
+ /*00b0:*/ 0x40, /* .#...... */
+ /*00b1:*/ 0x40, /* .#...... */
+ /*00b2:*/ 0x40, /* .#...... */
+ /*00b3:*/ 0x80, /* #....... */
+/* --- new character hyphen (45) starting at offset 0x00b4 --- */
+ /*00b4:*/ 5, 4, 1, 0, 4, /* width and bbox (w,h,x,y) */
+ /*00b9:*/ 0xf0, /* ####.... */
+/* --- new character period (46) starting at offset 0x00ba --- */
+ /*00ba:*/ 3, 1, 2, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00bf:*/ 0x80, /* #....... */
+ /*00c0:*/ 0x80, /* #....... */
+/* --- new character slash (47) starting at offset 0x00c1 --- */
+ /*00c1:*/ 4, 4, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*00c6:*/ 0x10, /* ...#.... */
+ /*00c7:*/ 0x10, /* ...#.... */
+ /*00c8:*/ 0x20, /* ..#..... */
+ /*00c9:*/ 0x20, /* ..#..... */
+ /*00ca:*/ 0x20, /* ..#..... */
+ /*00cb:*/ 0x40, /* .#...... */
+ /*00cc:*/ 0x40, /* .#...... */
+ /*00cd:*/ 0x40, /* .#...... */
+ /*00ce:*/ 0x80, /* #....... */
+ /*00cf:*/ 0x80, /* #....... */
+ /*00d0:*/ 0x80, /* #....... */
+/* --- new character zero (48) starting at offset 0x00d1 --- */
+ /*00d1:*/ 8, 6, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00d6:*/ 0x78, /* .####... */
+ /*00d7:*/ 0x84, /* #....#.. */
+ /*00d8:*/ 0x84, /* #....#.. */
+ /*00d9:*/ 0x84, /* #....#.. */
+ /*00da:*/ 0x84, /* #....#.. */
+ /*00db:*/ 0x84, /* #....#.. */
+ /*00dc:*/ 0x84, /* #....#.. */
+ /*00dd:*/ 0x84, /* #....#.. */
+ /*00de:*/ 0x84, /* #....#.. */
+ /*00df:*/ 0x78, /* .####... */
+/* --- new character one (49) starting at offset 0x00e0 --- */
+ /*00e0:*/ 8, 3, 10, 2, 0, /* width and bbox (w,h,x,y) */
+ /*00e5:*/ 0x20, /* ..#..... */
+ /*00e6:*/ 0xe0, /* ###..... */
+ /*00e7:*/ 0x20, /* ..#..... */
+ /*00e8:*/ 0x20, /* ..#..... */
+ /*00e9:*/ 0x20, /* ..#..... */
+ /*00ea:*/ 0x20, /* ..#..... */
+ /*00eb:*/ 0x20, /* ..#..... */
+ /*00ec:*/ 0x20, /* ..#..... */
+ /*00ed:*/ 0x20, /* ..#..... */
+ /*00ee:*/ 0x20, /* ..#..... */
+/* --- new character two (50) starting at offset 0x00ef --- */
+ /*00ef:*/ 8, 6, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00f4:*/ 0x78, /* .####... */
+ /*00f5:*/ 0x84, /* #....#.. */
+ /*00f6:*/ 0x84, /* #....#.. */
+ /*00f7:*/ 0x08, /* ....#... */
+ /*00f8:*/ 0x10, /* ...#.... */
+ /*00f9:*/ 0x20, /* ..#..... */
+ /*00fa:*/ 0x40, /* .#...... */
+ /*00fb:*/ 0x80, /* #....... */
+ /*00fc:*/ 0x80, /* #....... */
+ /*00fd:*/ 0xfc, /* ######.. */
+/* --- new character three (51) starting at offset 0x00fe --- */
+ /*00fe:*/ 8, 6, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0103:*/ 0x78, /* .####... */
+ /*0104:*/ 0x84, /* #....#.. */
+ /*0105:*/ 0x84, /* #....#.. */
+ /*0106:*/ 0x04, /* .....#.. */
+ /*0107:*/ 0x38, /* ..###... */
+ /*0108:*/ 0x04, /* .....#.. */
+ /*0109:*/ 0x04, /* .....#.. */
+ /*010a:*/ 0x84, /* #....#.. */
+ /*010b:*/ 0x84, /* #....#.. */
+ /*010c:*/ 0x78, /* .####... */
+/* --- new character four (52) starting at offset 0x010d --- */
+ /*010d:*/ 8, 7, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0112:*/ 0x0c, /* ....##.. */
+ /*0113:*/ 0x14, /* ...#.#.. */
+ /*0114:*/ 0x24, /* ..#..#.. */
+ /*0115:*/ 0x24, /* ..#..#.. */
+ /*0116:*/ 0x44, /* .#...#.. */
+ /*0117:*/ 0x84, /* #....#.. */
+ /*0118:*/ 0xfe, /* #######. */
+ /*0119:*/ 0x04, /* .....#.. */
+ /*011a:*/ 0x04, /* .....#.. */
+ /*011b:*/ 0x04, /* .....#.. */
+/* --- new character five (53) starting at offset 0x011c --- */
+ /*011c:*/ 8, 6, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0121:*/ 0xfc, /* ######.. */
+ /*0122:*/ 0x80, /* #....... */
+ /*0123:*/ 0x80, /* #....... */
+ /*0124:*/ 0x80, /* #....... */
+ /*0125:*/ 0xf8, /* #####... */
+ /*0126:*/ 0x04, /* .....#.. */
+ /*0127:*/ 0x04, /* .....#.. */
+ /*0128:*/ 0x84, /* #....#.. */
+ /*0129:*/ 0x84, /* #....#.. */
+ /*012a:*/ 0x78, /* .####... */
+/* --- new character six (54) starting at offset 0x012b --- */
+ /*012b:*/ 8, 6, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0130:*/ 0x78, /* .####... */
+ /*0131:*/ 0x84, /* #....#.. */
+ /*0132:*/ 0x80, /* #....... */
+ /*0133:*/ 0x80, /* #....... */
+ /*0134:*/ 0xb8, /* #.###... */
+ /*0135:*/ 0xc4, /* ##...#.. */
+ /*0136:*/ 0x84, /* #....#.. */
+ /*0137:*/ 0x84, /* #....#.. */
+ /*0138:*/ 0x84, /* #....#.. */
+ /*0139:*/ 0x78, /* .####... */
+/* --- new character seven (55) starting at offset 0x013a --- */
+ /*013a:*/ 8, 6, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*013f:*/ 0xfc, /* ######.. */
+ /*0140:*/ 0x04, /* .....#.. */
+ /*0141:*/ 0x08, /* ....#... */
+ /*0142:*/ 0x08, /* ....#... */
+ /*0143:*/ 0x10, /* ...#.... */
+ /*0144:*/ 0x10, /* ...#.... */
+ /*0145:*/ 0x20, /* ..#..... */
+ /*0146:*/ 0x20, /* ..#..... */
+ /*0147:*/ 0x40, /* .#...... */
+ /*0148:*/ 0x40, /* .#...... */
+/* --- new character eight (56) starting at offset 0x0149 --- */
+ /*0149:*/ 8, 6, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*014e:*/ 0x78, /* .####... */
+ /*014f:*/ 0x84, /* #....#.. */
+ /*0150:*/ 0x84, /* #....#.. */
+ /*0151:*/ 0x84, /* #....#.. */
+ /*0152:*/ 0x78, /* .####... */
+ /*0153:*/ 0x84, /* #....#.. */
+ /*0154:*/ 0x84, /* #....#.. */
+ /*0155:*/ 0x84, /* #....#.. */
+ /*0156:*/ 0x84, /* #....#.. */
+ /*0157:*/ 0x78, /* .####... */
+/* --- new character nine (57) starting at offset 0x0158 --- */
+ /*0158:*/ 8, 6, 10, 1, 0, /* width and bbox (w,h,x,y) */
+ /*015d:*/ 0x78, /* .####... */
+ /*015e:*/ 0x84, /* #....#.. */
+ /*015f:*/ 0x84, /* #....#.. */
+ /*0160:*/ 0x84, /* #....#.. */
+ /*0161:*/ 0x84, /* #....#.. */
+ /*0162:*/ 0x7c, /* .#####.. */
+ /*0163:*/ 0x04, /* .....#.. */
+ /*0164:*/ 0x84, /* #....#.. */
+ /*0165:*/ 0x84, /* #....#.. */
+ /*0166:*/ 0x78, /* .####... */
+/* --- new character colon (58) starting at offset 0x0167 --- */
+ /*0167:*/ 3, 1, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*016c:*/ 0x80, /* #....... */
+ /*016d:*/ 0x80, /* #....... */
+ /*016e:*/ 0x00, /* ........ */
+ /*016f:*/ 0x00, /* ........ */
+ /*0170:*/ 0x00, /* ........ */
+ /*0171:*/ 0x00, /* ........ */
+ /*0172:*/ 0x80, /* #....... */
+ /*0173:*/ 0x80, /* #....... */
+/* --- new character semicolon (59) starting at offset 0x0174 --- */
+ /*0174:*/ 4, 2, 10, 0, -2, /* width and bbox (w,h,x,y) */
+ /*0179:*/ 0x40, /* .#...... */
+ /*017a:*/ 0x40, /* .#...... */
+ /*017b:*/ 0x00, /* ........ */
+ /*017c:*/ 0x00, /* ........ */
+ /*017d:*/ 0x00, /* ........ */
+ /*017e:*/ 0x00, /* ........ */
+ /*017f:*/ 0x40, /* .#...... */
+ /*0180:*/ 0x40, /* .#...... */
+ /*0181:*/ 0x40, /* .#...... */
+ /*0182:*/ 0x80, /* #....... */
+/* --- new character less (60) starting at offset 0x0183 --- */
+ /*0183:*/ 8, 6, 5, 1, 2, /* width and bbox (w,h,x,y) */
+ /*0188:*/ 0x0c, /* ....##.. */
+ /*0189:*/ 0x30, /* ..##.... */
+ /*018a:*/ 0xc0, /* ##...... */
+ /*018b:*/ 0x30, /* ..##.... */
+ /*018c:*/ 0x0c, /* ....##.. */
+/* --- new character equal (61) starting at offset 0x018d --- */
+ /*018d:*/ 9, 6, 3, 1, 3, /* width and bbox (w,h,x,y) */
+ /*0192:*/ 0xfc, /* ######.. */
+ /*0193:*/ 0x00, /* ........ */
+ /*0194:*/ 0xfc, /* ######.. */
+/* --- new character greater (62) starting at offset 0x0195 --- */
+ /*0195:*/ 8, 6, 5, 1, 2, /* width and bbox (w,h,x,y) */
+ /*019a:*/ 0xc0, /* ##...... */
+ /*019b:*/ 0x30, /* ..##.... */
+ /*019c:*/ 0x0c, /* ....##.. */
+ /*019d:*/ 0x30, /* ..##.... */
+ /*019e:*/ 0xc0, /* ##...... */
+/* --- new character question (63) starting at offset 0x019f --- */
+ /*019f:*/ 8, 6, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01a4:*/ 0x30, /* ..##.... */
+ /*01a5:*/ 0xcc, /* ##..##.. */
+ /*01a6:*/ 0x84, /* #....#.. */
+ /*01a7:*/ 0x84, /* #....#.. */
+ /*01a8:*/ 0x04, /* .....#.. */
+ /*01a9:*/ 0x08, /* ....#... */
+ /*01aa:*/ 0x10, /* ...#.... */
+ /*01ab:*/ 0x20, /* ..#..... */
+ /*01ac:*/ 0x00, /* ........ */
+ /*01ad:*/ 0x20, /* ..#..... */
+ /*01ae:*/ 0x20, /* ..#..... */
+/* --- new character at (64) starting at offset 0x01af --- */
+ /*01af:*/ 13, 11, 12, 1, -1, /* width and bbox (w,h,x,y) */
+ /*01b4:*/ 0x0f,0x00, /* ....####........ */
+ /*01b6:*/ 0x30,0xc0, /* ..##....##...... */
+ /*01b8:*/ 0x40,0x20, /* .#........#..... */
+ /*01ba:*/ 0x46,0xa0, /* .#...##.#.#..... */
+ /*01bc:*/ 0x89,0x20, /* #...#..#..#..... */
+ /*01be:*/ 0x91,0x20, /* #..#...#..#..... */
+ /*01c0:*/ 0x91,0x20, /* #..#...#..#..... */
+ /*01c2:*/ 0x93,0x40, /* #..#..##.#...... */
+ /*01c4:*/ 0x8d,0x80, /* #...##.##....... */
+ /*01c6:*/ 0x40,0x00, /* .#.............. */
+ /*01c8:*/ 0x60,0x80, /* .##.....#....... */
+ /*01ca:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character A (65) starting at offset 0x01cc --- */
+ /*01cc:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01d1:*/ 0x08,0x00, /* ....#........... */
+ /*01d3:*/ 0x08,0x00, /* ....#........... */
+ /*01d5:*/ 0x14,0x00, /* ...#.#.......... */
+ /*01d7:*/ 0x14,0x00, /* ...#.#.......... */
+ /*01d9:*/ 0x22,0x00, /* ..#...#......... */
+ /*01db:*/ 0x22,0x00, /* ..#...#......... */
+ /*01dd:*/ 0x41,0x00, /* .#.....#........ */
+ /*01df:*/ 0x7f,0x00, /* .#######........ */
+ /*01e1:*/ 0x41,0x00, /* .#.....#........ */
+ /*01e3:*/ 0x80,0x80, /* #.......#....... */
+ /*01e5:*/ 0x80,0x80, /* #.......#....... */
+/* --- new character B (66) starting at offset 0x01e7 --- */
+ /*01e7:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01ec:*/ 0xfc, /* ######.. */
+ /*01ed:*/ 0x86, /* #....##. */
+ /*01ee:*/ 0x82, /* #.....#. */
+ /*01ef:*/ 0x82, /* #.....#. */
+ /*01f0:*/ 0x82, /* #.....#. */
+ /*01f1:*/ 0xfc, /* ######.. */
+ /*01f2:*/ 0x82, /* #.....#. */
+ /*01f3:*/ 0x82, /* #.....#. */
+ /*01f4:*/ 0x82, /* #.....#. */
+ /*01f5:*/ 0x82, /* #.....#. */
+ /*01f6:*/ 0xfc, /* ######.. */
+/* --- new character C (67) starting at offset 0x01f7 --- */
+ /*01f7:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01fc:*/ 0x1c, /* ...###.. */
+ /*01fd:*/ 0x63, /* .##...## */
+ /*01fe:*/ 0x41, /* .#.....# */
+ /*01ff:*/ 0x80, /* #....... */
+ /*0200:*/ 0x80, /* #....... */
+ /*0201:*/ 0x80, /* #....... */
+ /*0202:*/ 0x80, /* #....... */
+ /*0203:*/ 0x80, /* #....... */
+ /*0204:*/ 0x41, /* .#.....# */
+ /*0205:*/ 0x63, /* .##...## */
+ /*0206:*/ 0x1c, /* ...###.. */
+/* --- new character D (68) starting at offset 0x0207 --- */
+ /*0207:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*020c:*/ 0xf8, /* #####... */
+ /*020d:*/ 0x86, /* #....##. */
+ /*020e:*/ 0x82, /* #.....#. */
+ /*020f:*/ 0x81, /* #......# */
+ /*0210:*/ 0x81, /* #......# */
+ /*0211:*/ 0x81, /* #......# */
+ /*0212:*/ 0x81, /* #......# */
+ /*0213:*/ 0x81, /* #......# */
+ /*0214:*/ 0x82, /* #.....#. */
+ /*0215:*/ 0x86, /* #....##. */
+ /*0216:*/ 0xf8, /* #####... */
+/* --- new character E (69) starting at offset 0x0217 --- */
+ /*0217:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*021c:*/ 0xfe, /* #######. */
+ /*021d:*/ 0x80, /* #....... */
+ /*021e:*/ 0x80, /* #....... */
+ /*021f:*/ 0x80, /* #....... */
+ /*0220:*/ 0x80, /* #....... */
+ /*0221:*/ 0xfc, /* ######.. */
+ /*0222:*/ 0x80, /* #....... */
+ /*0223:*/ 0x80, /* #....... */
+ /*0224:*/ 0x80, /* #....... */
+ /*0225:*/ 0x80, /* #....... */
+ /*0226:*/ 0xfe, /* #######. */
+/* --- new character F (70) starting at offset 0x0227 --- */
+ /*0227:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*022c:*/ 0xfe, /* #######. */
+ /*022d:*/ 0x80, /* #....... */
+ /*022e:*/ 0x80, /* #....... */
+ /*022f:*/ 0x80, /* #....... */
+ /*0230:*/ 0x80, /* #....... */
+ /*0231:*/ 0xfc, /* ######.. */
+ /*0232:*/ 0x80, /* #....... */
+ /*0233:*/ 0x80, /* #....... */
+ /*0234:*/ 0x80, /* #....... */
+ /*0235:*/ 0x80, /* #....... */
+ /*0236:*/ 0x80, /* #....... */
+/* --- new character G (71) starting at offset 0x0237 --- */
+ /*0237:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*023c:*/ 0x1e,0x00, /* ...####......... */
+ /*023e:*/ 0x61,0x80, /* .##....##....... */
+ /*0240:*/ 0x40,0x80, /* .#......#....... */
+ /*0242:*/ 0x80,0x00, /* #............... */
+ /*0244:*/ 0x80,0x00, /* #............... */
+ /*0246:*/ 0x87,0x80, /* #....####....... */
+ /*0248:*/ 0x80,0x80, /* #.......#....... */
+ /*024a:*/ 0x80,0x80, /* #.......#....... */
+ /*024c:*/ 0x40,0x80, /* .#......#....... */
+ /*024e:*/ 0x63,0x80, /* .##...###....... */
+ /*0250:*/ 0x1c,0x80, /* ...###..#....... */
+/* --- new character H (72) starting at offset 0x0252 --- */
+ /*0252:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0257:*/ 0x81, /* #......# */
+ /*0258:*/ 0x81, /* #......# */
+ /*0259:*/ 0x81, /* #......# */
+ /*025a:*/ 0x81, /* #......# */
+ /*025b:*/ 0x81, /* #......# */
+ /*025c:*/ 0xff, /* ######## */
+ /*025d:*/ 0x81, /* #......# */
+ /*025e:*/ 0x81, /* #......# */
+ /*025f:*/ 0x81, /* #......# */
+ /*0260:*/ 0x81, /* #......# */
+ /*0261:*/ 0x81, /* #......# */
+/* --- new character I (73) starting at offset 0x0262 --- */
+ /*0262:*/ 5, 1, 11, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0267:*/ 0x80, /* #....... */
+ /*0268:*/ 0x80, /* #....... */
+ /*0269:*/ 0x80, /* #....... */
+ /*026a:*/ 0x80, /* #....... */
+ /*026b:*/ 0x80, /* #....... */
+ /*026c:*/ 0x80, /* #....... */
+ /*026d:*/ 0x80, /* #....... */
+ /*026e:*/ 0x80, /* #....... */
+ /*026f:*/ 0x80, /* #....... */
+ /*0270:*/ 0x80, /* #....... */
+ /*0271:*/ 0x80, /* #....... */
+/* --- new character J (74) starting at offset 0x0272 --- */
+ /*0272:*/ 8, 6, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0277:*/ 0x04, /* .....#.. */
+ /*0278:*/ 0x04, /* .....#.. */
+ /*0279:*/ 0x04, /* .....#.. */
+ /*027a:*/ 0x04, /* .....#.. */
+ /*027b:*/ 0x04, /* .....#.. */
+ /*027c:*/ 0x04, /* .....#.. */
+ /*027d:*/ 0x04, /* .....#.. */
+ /*027e:*/ 0x04, /* .....#.. */
+ /*027f:*/ 0x84, /* #....#.. */
+ /*0280:*/ 0x84, /* #....#.. */
+ /*0281:*/ 0x78, /* .####... */
+/* --- new character K (75) starting at offset 0x0282 --- */
+ /*0282:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0287:*/ 0x82, /* #.....#. */
+ /*0288:*/ 0x84, /* #....#.. */
+ /*0289:*/ 0x88, /* #...#... */
+ /*028a:*/ 0x90, /* #..#.... */
+ /*028b:*/ 0xa0, /* #.#..... */
+ /*028c:*/ 0xe0, /* ###..... */
+ /*028d:*/ 0x90, /* #..#.... */
+ /*028e:*/ 0x88, /* #...#... */
+ /*028f:*/ 0x84, /* #....#.. */
+ /*0290:*/ 0x82, /* #.....#. */
+ /*0291:*/ 0x81, /* #......# */
+/* --- new character L (76) starting at offset 0x0292 --- */
+ /*0292:*/ 8, 6, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0297:*/ 0x80, /* #....... */
+ /*0298:*/ 0x80, /* #....... */
+ /*0299:*/ 0x80, /* #....... */
+ /*029a:*/ 0x80, /* #....... */
+ /*029b:*/ 0x80, /* #....... */
+ /*029c:*/ 0x80, /* #....... */
+ /*029d:*/ 0x80, /* #....... */
+ /*029e:*/ 0x80, /* #....... */
+ /*029f:*/ 0x80, /* #....... */
+ /*02a0:*/ 0x80, /* #....... */
+ /*02a1:*/ 0xfc, /* ######.. */
+/* --- new character M (77) starting at offset 0x02a2 --- */
+ /*02a2:*/ 13, 11, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02a7:*/ 0x80,0x20, /* #.........#..... */
+ /*02a9:*/ 0x80,0x20, /* #.........#..... */
+ /*02ab:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02ad:*/ 0xa0,0xa0, /* #.#.....#.#..... */
+ /*02af:*/ 0xa0,0xa0, /* #.#.....#.#..... */
+ /*02b1:*/ 0x91,0x20, /* #..#...#..#..... */
+ /*02b3:*/ 0x91,0x20, /* #..#...#..#..... */
+ /*02b5:*/ 0x8a,0x20, /* #...#.#...#..... */
+ /*02b7:*/ 0x8a,0x20, /* #...#.#...#..... */
+ /*02b9:*/ 0x84,0x20, /* #....#....#..... */
+ /*02bb:*/ 0x84,0x20, /* #....#....#..... */
+/* --- new character N (78) starting at offset 0x02bd --- */
+ /*02bd:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02c2:*/ 0xc1, /* ##.....# */
+ /*02c3:*/ 0xc1, /* ##.....# */
+ /*02c4:*/ 0xa1, /* #.#....# */
+ /*02c5:*/ 0x91, /* #..#...# */
+ /*02c6:*/ 0x91, /* #..#...# */
+ /*02c7:*/ 0x89, /* #...#..# */
+ /*02c8:*/ 0x89, /* #...#..# */
+ /*02c9:*/ 0x85, /* #....#.# */
+ /*02ca:*/ 0x85, /* #....#.# */
+ /*02cb:*/ 0x83, /* #.....## */
+ /*02cc:*/ 0x83, /* #.....## */
+/* --- new character O (79) starting at offset 0x02cd --- */
+ /*02cd:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02d2:*/ 0x1c,0x00, /* ...###.......... */
+ /*02d4:*/ 0x63,0x00, /* .##...##........ */
+ /*02d6:*/ 0x41,0x00, /* .#.....#........ */
+ /*02d8:*/ 0x80,0x80, /* #.......#....... */
+ /*02da:*/ 0x80,0x80, /* #.......#....... */
+ /*02dc:*/ 0x80,0x80, /* #.......#....... */
+ /*02de:*/ 0x80,0x80, /* #.......#....... */
+ /*02e0:*/ 0x80,0x80, /* #.......#....... */
+ /*02e2:*/ 0x41,0x00, /* .#.....#........ */
+ /*02e4:*/ 0x63,0x00, /* .##...##........ */
+ /*02e6:*/ 0x1c,0x00, /* ...###.......... */
+/* --- new character P (80) starting at offset 0x02e8 --- */
+ /*02e8:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02ed:*/ 0xfc, /* ######.. */
+ /*02ee:*/ 0x86, /* #....##. */
+ /*02ef:*/ 0x82, /* #.....#. */
+ /*02f0:*/ 0x82, /* #.....#. */
+ /*02f1:*/ 0x86, /* #....##. */
+ /*02f2:*/ 0xfc, /* ######.. */
+ /*02f3:*/ 0x80, /* #....... */
+ /*02f4:*/ 0x80, /* #....... */
+ /*02f5:*/ 0x80, /* #....... */
+ /*02f6:*/ 0x80, /* #....... */
+ /*02f7:*/ 0x80, /* #....... */
+/* --- new character Q (81) starting at offset 0x02f8 --- */
+ /*02f8:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02fd:*/ 0x1c,0x00, /* ...###.......... */
+ /*02ff:*/ 0x63,0x00, /* .##...##........ */
+ /*0301:*/ 0x41,0x00, /* .#.....#........ */
+ /*0303:*/ 0x80,0x80, /* #.......#....... */
+ /*0305:*/ 0x80,0x80, /* #.......#....... */
+ /*0307:*/ 0x80,0x80, /* #.......#....... */
+ /*0309:*/ 0x88,0x80, /* #...#...#....... */
+ /*030b:*/ 0x84,0x80, /* #....#..#....... */
+ /*030d:*/ 0x43,0x00, /* .#....##........ */
+ /*030f:*/ 0x63,0x00, /* .##...##........ */
+ /*0311:*/ 0x1c,0x80, /* ...###..#....... */
+/* --- new character R (82) starting at offset 0x0313 --- */
+ /*0313:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0318:*/ 0xfc, /* ######.. */
+ /*0319:*/ 0x86, /* #....##. */
+ /*031a:*/ 0x82, /* #.....#. */
+ /*031b:*/ 0x82, /* #.....#. */
+ /*031c:*/ 0x84, /* #....#.. */
+ /*031d:*/ 0xf8, /* #####... */
+ /*031e:*/ 0x84, /* #....#.. */
+ /*031f:*/ 0x82, /* #.....#. */
+ /*0320:*/ 0x82, /* #.....#. */
+ /*0321:*/ 0x82, /* #.....#. */
+ /*0322:*/ 0x82, /* #.....#. */
+/* --- new character S (83) starting at offset 0x0323 --- */
+ /*0323:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0328:*/ 0x38, /* ..###... */
+ /*0329:*/ 0xc6, /* ##...##. */
+ /*032a:*/ 0x82, /* #.....#. */
+ /*032b:*/ 0x80, /* #....... */
+ /*032c:*/ 0x60, /* .##..... */
+ /*032d:*/ 0x18, /* ...##... */
+ /*032e:*/ 0x06, /* .....##. */
+ /*032f:*/ 0x02, /* ......#. */
+ /*0330:*/ 0x82, /* #.....#. */
+ /*0331:*/ 0xc6, /* ##...##. */
+ /*0332:*/ 0x38, /* ..###... */
+/* --- new character T (84) starting at offset 0x0333 --- */
+ /*0333:*/ 9, 9, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0338:*/ 0xff,0x80, /* #########....... */
+ /*033a:*/ 0x08,0x00, /* ....#........... */
+ /*033c:*/ 0x08,0x00, /* ....#........... */
+ /*033e:*/ 0x08,0x00, /* ....#........... */
+ /*0340:*/ 0x08,0x00, /* ....#........... */
+ /*0342:*/ 0x08,0x00, /* ....#........... */
+ /*0344:*/ 0x08,0x00, /* ....#........... */
+ /*0346:*/ 0x08,0x00, /* ....#........... */
+ /*0348:*/ 0x08,0x00, /* ....#........... */
+ /*034a:*/ 0x08,0x00, /* ....#........... */
+ /*034c:*/ 0x08,0x00, /* ....#........... */
+/* --- new character U (85) starting at offset 0x034e --- */
+ /*034e:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0353:*/ 0x81, /* #......# */
+ /*0354:*/ 0x81, /* #......# */
+ /*0355:*/ 0x81, /* #......# */
+ /*0356:*/ 0x81, /* #......# */
+ /*0357:*/ 0x81, /* #......# */
+ /*0358:*/ 0x81, /* #......# */
+ /*0359:*/ 0x81, /* #......# */
+ /*035a:*/ 0x81, /* #......# */
+ /*035b:*/ 0x81, /* #......# */
+ /*035c:*/ 0x42, /* .#....#. */
+ /*035d:*/ 0x3c, /* ..####.. */
+/* --- new character V (86) starting at offset 0x035e --- */
+ /*035e:*/ 11, 9, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0363:*/ 0x80,0x80, /* #.......#....... */
+ /*0365:*/ 0x80,0x80, /* #.......#....... */
+ /*0367:*/ 0x41,0x00, /* .#.....#........ */
+ /*0369:*/ 0x41,0x00, /* .#.....#........ */
+ /*036b:*/ 0x22,0x00, /* ..#...#......... */
+ /*036d:*/ 0x22,0x00, /* ..#...#......... */
+ /*036f:*/ 0x22,0x00, /* ..#...#......... */
+ /*0371:*/ 0x14,0x00, /* ...#.#.......... */
+ /*0373:*/ 0x14,0x00, /* ...#.#.......... */
+ /*0375:*/ 0x08,0x00, /* ....#........... */
+ /*0377:*/ 0x08,0x00, /* ....#........... */
+/* --- new character W (87) starting at offset 0x0379 --- */
+ /*0379:*/ 15, 13, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*037e:*/ 0x82,0x08, /* #.....#.....#... */
+ /*0380:*/ 0x82,0x08, /* #.....#.....#... */
+ /*0382:*/ 0x85,0x08, /* #....#.#....#... */
+ /*0384:*/ 0x45,0x10, /* .#...#.#...#.... */
+ /*0386:*/ 0x45,0x10, /* .#...#.#...#.... */
+ /*0388:*/ 0x45,0x10, /* .#...#.#...#.... */
+ /*038a:*/ 0x28,0xa0, /* ..#.#...#.#..... */
+ /*038c:*/ 0x28,0xa0, /* ..#.#...#.#..... */
+ /*038e:*/ 0x28,0xa0, /* ..#.#...#.#..... */
+ /*0390:*/ 0x10,0x40, /* ...#.....#...... */
+ /*0392:*/ 0x10,0x40, /* ...#.....#...... */
+/* --- new character X (88) starting at offset 0x0394 --- */
+ /*0394:*/ 10, 8, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0399:*/ 0x81, /* #......# */
+ /*039a:*/ 0x81, /* #......# */
+ /*039b:*/ 0x42, /* .#....#. */
+ /*039c:*/ 0x24, /* ..#..#.. */
+ /*039d:*/ 0x18, /* ...##... */
+ /*039e:*/ 0x18, /* ...##... */
+ /*039f:*/ 0x24, /* ..#..#.. */
+ /*03a0:*/ 0x42, /* .#....#. */
+ /*03a1:*/ 0x42, /* .#....#. */
+ /*03a2:*/ 0x81, /* #......# */
+ /*03a3:*/ 0x81, /* #......# */
+/* --- new character Y (89) starting at offset 0x03a4 --- */
+ /*03a4:*/ 9, 9, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03a9:*/ 0x80,0x80, /* #.......#....... */
+ /*03ab:*/ 0x41,0x00, /* .#.....#........ */
+ /*03ad:*/ 0x41,0x00, /* .#.....#........ */
+ /*03af:*/ 0x22,0x00, /* ..#...#......... */
+ /*03b1:*/ 0x22,0x00, /* ..#...#......... */
+ /*03b3:*/ 0x14,0x00, /* ...#.#.......... */
+ /*03b5:*/ 0x08,0x00, /* ....#........... */
+ /*03b7:*/ 0x08,0x00, /* ....#........... */
+ /*03b9:*/ 0x08,0x00, /* ....#........... */
+ /*03bb:*/ 0x08,0x00, /* ....#........... */
+ /*03bd:*/ 0x08,0x00, /* ....#........... */
+/* --- new character Z (90) starting at offset 0x03bf --- */
+ /*03bf:*/ 9, 7, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*03c4:*/ 0xfe, /* #######. */
+ /*03c5:*/ 0x02, /* ......#. */
+ /*03c6:*/ 0x04, /* .....#.. */
+ /*03c7:*/ 0x08, /* ....#... */
+ /*03c8:*/ 0x18, /* ...##... */
+ /*03c9:*/ 0x10, /* ...#.... */
+ /*03ca:*/ 0x20, /* ..#..... */
+ /*03cb:*/ 0x60, /* .##..... */
+ /*03cc:*/ 0x40, /* .#...... */
+ /*03cd:*/ 0x80, /* #....... */
+ /*03ce:*/ 0xfe, /* #######. */
+/* --- new character bracketleft (91) starting at offset 0x03cf --- */
+ /*03cf:*/ 4, 3, 14, 1, -3, /* width and bbox (w,h,x,y) */
+ /*03d4:*/ 0xe0, /* ###..... */
+ /*03d5:*/ 0x80, /* #....... */
+ /*03d6:*/ 0x80, /* #....... */
+ /*03d7:*/ 0x80, /* #....... */
+ /*03d8:*/ 0x80, /* #....... */
+ /*03d9:*/ 0x80, /* #....... */
+ /*03da:*/ 0x80, /* #....... */
+ /*03db:*/ 0x80, /* #....... */
+ /*03dc:*/ 0x80, /* #....... */
+ /*03dd:*/ 0x80, /* #....... */
+ /*03de:*/ 0x80, /* #....... */
+ /*03df:*/ 0x80, /* #....... */
+ /*03e0:*/ 0x80, /* #....... */
+ /*03e1:*/ 0xe0, /* ###..... */
+/* --- new character backslash (92) starting at offset 0x03e2 --- */
+ /*03e2:*/ 4, 4, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*03e7:*/ 0x80, /* #....... */
+ /*03e8:*/ 0x80, /* #....... */
+ /*03e9:*/ 0x40, /* .#...... */
+ /*03ea:*/ 0x40, /* .#...... */
+ /*03eb:*/ 0x40, /* .#...... */
+ /*03ec:*/ 0x20, /* ..#..... */
+ /*03ed:*/ 0x20, /* ..#..... */
+ /*03ee:*/ 0x20, /* ..#..... */
+ /*03ef:*/ 0x10, /* ...#.... */
+ /*03f0:*/ 0x10, /* ...#.... */
+ /*03f1:*/ 0x10, /* ...#.... */
+/* --- new character bracketright (93) starting at offset 0x03f2 --- */
+ /*03f2:*/ 4, 3, 14, 0, -3, /* width and bbox (w,h,x,y) */
+ /*03f7:*/ 0xe0, /* ###..... */
+ /*03f8:*/ 0x20, /* ..#..... */
+ /*03f9:*/ 0x20, /* ..#..... */
+ /*03fa:*/ 0x20, /* ..#..... */
+ /*03fb:*/ 0x20, /* ..#..... */
+ /*03fc:*/ 0x20, /* ..#..... */
+ /*03fd:*/ 0x20, /* ..#..... */
+ /*03fe:*/ 0x20, /* ..#..... */
+ /*03ff:*/ 0x20, /* ..#..... */
+ /*0400:*/ 0x20, /* ..#..... */
+ /*0401:*/ 0x20, /* ..#..... */
+ /*0402:*/ 0x20, /* ..#..... */
+ /*0403:*/ 0x20, /* ..#..... */
+ /*0404:*/ 0xe0, /* ###..... */
+/* --- new character asciicircum (94) starting at offset 0x0405 --- */
+ /*0405:*/ 7, 7, 4, 0, 6, /* width and bbox (w,h,x,y) */
+ /*040a:*/ 0x10, /* ...#.... */
+ /*040b:*/ 0x28, /* ..#.#... */
+ /*040c:*/ 0x44, /* .#...#.. */
+ /*040d:*/ 0x82, /* #.....#. */
+/* --- new character underscore (95) starting at offset 0x040e --- */
+ /*040e:*/ 8, 8, 1, 0, -3, /* width and bbox (w,h,x,y) */
+ /*0413:*/ 0xff, /* ######## */
+/* --- new character grave (96) starting at offset 0x0414 --- */
+ /*0414:*/ 5, 2, 2, 1, 9, /* width and bbox (w,h,x,y) */
+ /*0419:*/ 0x80, /* #....... */
+ /*041a:*/ 0x40, /* .#...... */
+/* --- new character a (97) starting at offset 0x041b --- */
+ /*041b:*/ 8, 7, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0420:*/ 0x78, /* .####... */
+ /*0421:*/ 0xcc, /* ##..##.. */
+ /*0422:*/ 0x04, /* .....#.. */
+ /*0423:*/ 0x7c, /* .#####.. */
+ /*0424:*/ 0xc4, /* ##...#.. */
+ /*0425:*/ 0x84, /* #....#.. */
+ /*0426:*/ 0xcc, /* ##..##.. */
+ /*0427:*/ 0x76, /* .###.##. */
+/* --- new character b (98) starting at offset 0x0428 --- */
+ /*0428:*/ 8, 6, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*042d:*/ 0x80, /* #....... */
+ /*042e:*/ 0x80, /* #....... */
+ /*042f:*/ 0x80, /* #....... */
+ /*0430:*/ 0xb8, /* #.###... */
+ /*0431:*/ 0xcc, /* ##..##.. */
+ /*0432:*/ 0x84, /* #....#.. */
+ /*0433:*/ 0x84, /* #....#.. */
+ /*0434:*/ 0x84, /* #....#.. */
+ /*0435:*/ 0x84, /* #....#.. */
+ /*0436:*/ 0xcc, /* ##..##.. */
+ /*0437:*/ 0xb8, /* #.###... */
+/* --- new character c (99) starting at offset 0x0438 --- */
+ /*0438:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*043d:*/ 0x78, /* .####... */
+ /*043e:*/ 0xcc, /* ##..##.. */
+ /*043f:*/ 0x80, /* #....... */
+ /*0440:*/ 0x80, /* #....... */
+ /*0441:*/ 0x80, /* #....... */
+ /*0442:*/ 0x84, /* #....#.. */
+ /*0443:*/ 0xcc, /* ##..##.. */
+ /*0444:*/ 0x78, /* .####... */
+/* --- new character d (100) starting at offset 0x0445 --- */
+ /*0445:*/ 8, 6, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*044a:*/ 0x04, /* .....#.. */
+ /*044b:*/ 0x04, /* .....#.. */
+ /*044c:*/ 0x04, /* .....#.. */
+ /*044d:*/ 0x74, /* .###.#.. */
+ /*044e:*/ 0xcc, /* ##..##.. */
+ /*044f:*/ 0x84, /* #....#.. */
+ /*0450:*/ 0x84, /* #....#.. */
+ /*0451:*/ 0x84, /* #....#.. */
+ /*0452:*/ 0x84, /* #....#.. */
+ /*0453:*/ 0xcc, /* ##..##.. */
+ /*0454:*/ 0x74, /* .###.#.. */
+/* --- new character e (101) starting at offset 0x0455 --- */
+ /*0455:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*045a:*/ 0x78, /* .####... */
+ /*045b:*/ 0xcc, /* ##..##.. */
+ /*045c:*/ 0x84, /* #....#.. */
+ /*045d:*/ 0xfc, /* ######.. */
+ /*045e:*/ 0x80, /* #....... */
+ /*045f:*/ 0x80, /* #....... */
+ /*0460:*/ 0xcc, /* ##..##.. */
+ /*0461:*/ 0x78, /* .####... */
+/* --- new character f (102) starting at offset 0x0462 --- */
+ /*0462:*/ 3, 4, 11, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0467:*/ 0x30, /* ..##.... */
+ /*0468:*/ 0x40, /* .#...... */
+ /*0469:*/ 0x40, /* .#...... */
+ /*046a:*/ 0xe0, /* ###..... */
+ /*046b:*/ 0x40, /* .#...... */
+ /*046c:*/ 0x40, /* .#...... */
+ /*046d:*/ 0x40, /* .#...... */
+ /*046e:*/ 0x40, /* .#...... */
+ /*046f:*/ 0x40, /* .#...... */
+ /*0470:*/ 0x40, /* .#...... */
+ /*0471:*/ 0x40, /* .#...... */
+/* --- new character g (103) starting at offset 0x0472 --- */
+ /*0472:*/ 8, 6, 11, 1, -3, /* width and bbox (w,h,x,y) */
+ /*0477:*/ 0x74, /* .###.#.. */
+ /*0478:*/ 0xcc, /* ##..##.. */
+ /*0479:*/ 0x84, /* #....#.. */
+ /*047a:*/ 0x84, /* #....#.. */
+ /*047b:*/ 0x84, /* #....#.. */
+ /*047c:*/ 0x84, /* #....#.. */
+ /*047d:*/ 0xcc, /* ##..##.. */
+ /*047e:*/ 0x74, /* .###.#.. */
+ /*047f:*/ 0x04, /* .....#.. */
+ /*0480:*/ 0xcc, /* ##..##.. */
+ /*0481:*/ 0x78, /* .####... */
+/* --- new character h (104) starting at offset 0x0482 --- */
+ /*0482:*/ 8, 6, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0487:*/ 0x80, /* #....... */
+ /*0488:*/ 0x80, /* #....... */
+ /*0489:*/ 0x80, /* #....... */
+ /*048a:*/ 0xb8, /* #.###... */
+ /*048b:*/ 0xcc, /* ##..##.. */
+ /*048c:*/ 0x84, /* #....#.. */
+ /*048d:*/ 0x84, /* #....#.. */
+ /*048e:*/ 0x84, /* #....#.. */
+ /*048f:*/ 0x84, /* #....#.. */
+ /*0490:*/ 0x84, /* #....#.. */
+ /*0491:*/ 0x84, /* #....#.. */
+/* --- new character i (105) starting at offset 0x0492 --- */
+ /*0492:*/ 3, 1, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0497:*/ 0x80, /* #....... */
+ /*0498:*/ 0x80, /* #....... */
+ /*0499:*/ 0x00, /* ........ */
+ /*049a:*/ 0x80, /* #....... */
+ /*049b:*/ 0x80, /* #....... */
+ /*049c:*/ 0x80, /* #....... */
+ /*049d:*/ 0x80, /* #....... */
+ /*049e:*/ 0x80, /* #....... */
+ /*049f:*/ 0x80, /* #....... */
+ /*04a0:*/ 0x80, /* #....... */
+ /*04a1:*/ 0x80, /* #....... */
+/* --- new character j (106) starting at offset 0x04a2 --- */
+ /*04a2:*/ 3, 3, 14, -1, -3, /* width and bbox (w,h,x,y) */
+ /*04a7:*/ 0x20, /* ..#..... */
+ /*04a8:*/ 0x20, /* ..#..... */
+ /*04a9:*/ 0x00, /* ........ */
+ /*04aa:*/ 0x20, /* ..#..... */
+ /*04ab:*/ 0x20, /* ..#..... */
+ /*04ac:*/ 0x20, /* ..#..... */
+ /*04ad:*/ 0x20, /* ..#..... */
+ /*04ae:*/ 0x20, /* ..#..... */
+ /*04af:*/ 0x20, /* ..#..... */
+ /*04b0:*/ 0x20, /* ..#..... */
+ /*04b1:*/ 0x20, /* ..#..... */
+ /*04b2:*/ 0x20, /* ..#..... */
+ /*04b3:*/ 0x20, /* ..#..... */
+ /*04b4:*/ 0xc0, /* ##...... */
+/* --- new character k (107) starting at offset 0x04b5 --- */
+ /*04b5:*/ 7, 6, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04ba:*/ 0x80, /* #....... */
+ /*04bb:*/ 0x80, /* #....... */
+ /*04bc:*/ 0x80, /* #....... */
+ /*04bd:*/ 0x88, /* #...#... */
+ /*04be:*/ 0x90, /* #..#.... */
+ /*04bf:*/ 0xa0, /* #.#..... */
+ /*04c0:*/ 0xc0, /* ##...... */
+ /*04c1:*/ 0xa0, /* #.#..... */
+ /*04c2:*/ 0x90, /* #..#.... */
+ /*04c3:*/ 0x88, /* #...#... */
+ /*04c4:*/ 0x84, /* #....#.. */
+/* --- new character l (108) starting at offset 0x04c5 --- */
+ /*04c5:*/ 3, 1, 11, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04ca:*/ 0x80, /* #....... */
+ /*04cb:*/ 0x80, /* #....... */
+ /*04cc:*/ 0x80, /* #....... */
+ /*04cd:*/ 0x80, /* #....... */
+ /*04ce:*/ 0x80, /* #....... */
+ /*04cf:*/ 0x80, /* #....... */
+ /*04d0:*/ 0x80, /* #....... */
+ /*04d1:*/ 0x80, /* #....... */
+ /*04d2:*/ 0x80, /* #....... */
+ /*04d3:*/ 0x80, /* #....... */
+ /*04d4:*/ 0x80, /* #....... */
+/* --- new character m (109) starting at offset 0x04d5 --- */
+ /*04d5:*/ 11, 9, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04da:*/ 0xb3,0x00, /* #.##..##........ */
+ /*04dc:*/ 0xcc,0x80, /* ##..##..#....... */
+ /*04de:*/ 0x88,0x80, /* #...#...#....... */
+ /*04e0:*/ 0x88,0x80, /* #...#...#....... */
+ /*04e2:*/ 0x88,0x80, /* #...#...#....... */
+ /*04e4:*/ 0x88,0x80, /* #...#...#....... */
+ /*04e6:*/ 0x88,0x80, /* #...#...#....... */
+ /*04e8:*/ 0x88,0x80, /* #...#...#....... */
+/* --- new character n (110) starting at offset 0x04ea --- */
+ /*04ea:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04ef:*/ 0xb8, /* #.###... */
+ /*04f0:*/ 0xcc, /* ##..##.. */
+ /*04f1:*/ 0x84, /* #....#.. */
+ /*04f2:*/ 0x84, /* #....#.. */
+ /*04f3:*/ 0x84, /* #....#.. */
+ /*04f4:*/ 0x84, /* #....#.. */
+ /*04f5:*/ 0x84, /* #....#.. */
+ /*04f6:*/ 0x84, /* #....#.. */
+/* --- new character o (111) starting at offset 0x04f7 --- */
+ /*04f7:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04fc:*/ 0x78, /* .####... */
+ /*04fd:*/ 0xcc, /* ##..##.. */
+ /*04fe:*/ 0x84, /* #....#.. */
+ /*04ff:*/ 0x84, /* #....#.. */
+ /*0500:*/ 0x84, /* #....#.. */
+ /*0501:*/ 0x84, /* #....#.. */
+ /*0502:*/ 0xcc, /* ##..##.. */
+ /*0503:*/ 0x78, /* .####... */
+/* --- new character p (112) starting at offset 0x0504 --- */
+ /*0504:*/ 8, 6, 11, 1, -3, /* width and bbox (w,h,x,y) */
+ /*0509:*/ 0xb8, /* #.###... */
+ /*050a:*/ 0xcc, /* ##..##.. */
+ /*050b:*/ 0x84, /* #....#.. */
+ /*050c:*/ 0x84, /* #....#.. */
+ /*050d:*/ 0x84, /* #....#.. */
+ /*050e:*/ 0x84, /* #....#.. */
+ /*050f:*/ 0xcc, /* ##..##.. */
+ /*0510:*/ 0xb8, /* #.###... */
+ /*0511:*/ 0x80, /* #....... */
+ /*0512:*/ 0x80, /* #....... */
+ /*0513:*/ 0x80, /* #....... */
+/* --- new character q (113) starting at offset 0x0514 --- */
+ /*0514:*/ 8, 6, 11, 1, -3, /* width and bbox (w,h,x,y) */
+ /*0519:*/ 0x74, /* .###.#.. */
+ /*051a:*/ 0xcc, /* ##..##.. */
+ /*051b:*/ 0x84, /* #....#.. */
+ /*051c:*/ 0x84, /* #....#.. */
+ /*051d:*/ 0x84, /* #....#.. */
+ /*051e:*/ 0x84, /* #....#.. */
+ /*051f:*/ 0xcc, /* ##..##.. */
+ /*0520:*/ 0x74, /* .###.#.. */
+ /*0521:*/ 0x04, /* .....#.. */
+ /*0522:*/ 0x04, /* .....#.. */
+ /*0523:*/ 0x04, /* .....#.. */
+/* --- new character r (114) starting at offset 0x0524 --- */
+ /*0524:*/ 5, 4, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0529:*/ 0xb0, /* #.##.... */
+ /*052a:*/ 0xc0, /* ##...... */
+ /*052b:*/ 0x80, /* #....... */
+ /*052c:*/ 0x80, /* #....... */
+ /*052d:*/ 0x80, /* #....... */
+ /*052e:*/ 0x80, /* #....... */
+ /*052f:*/ 0x80, /* #....... */
+ /*0530:*/ 0x80, /* #....... */
+/* --- new character s (115) starting at offset 0x0531 --- */
+ /*0531:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0536:*/ 0x78, /* .####... */
+ /*0537:*/ 0x84, /* #....#.. */
+ /*0538:*/ 0x80, /* #....... */
+ /*0539:*/ 0x78, /* .####... */
+ /*053a:*/ 0x0c, /* ....##.. */
+ /*053b:*/ 0x04, /* .....#.. */
+ /*053c:*/ 0x84, /* #....#.. */
+ /*053d:*/ 0x78, /* .####... */
+/* --- new character t (116) starting at offset 0x053e --- */
+ /*053e:*/ 4, 4, 10, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0543:*/ 0x40, /* .#...... */
+ /*0544:*/ 0x40, /* .#...... */
+ /*0545:*/ 0xf0, /* ####.... */
+ /*0546:*/ 0x40, /* .#...... */
+ /*0547:*/ 0x40, /* .#...... */
+ /*0548:*/ 0x40, /* .#...... */
+ /*0549:*/ 0x40, /* .#...... */
+ /*054a:*/ 0x40, /* .#...... */
+ /*054b:*/ 0x40, /* .#...... */
+ /*054c:*/ 0x30, /* ..##.... */
+/* --- new character u (117) starting at offset 0x054d --- */
+ /*054d:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0552:*/ 0x84, /* #....#.. */
+ /*0553:*/ 0x84, /* #....#.. */
+ /*0554:*/ 0x84, /* #....#.. */
+ /*0555:*/ 0x84, /* #....#.. */
+ /*0556:*/ 0x84, /* #....#.. */
+ /*0557:*/ 0x84, /* #....#.. */
+ /*0558:*/ 0xcc, /* ##..##.. */
+ /*0559:*/ 0x74, /* .###.#.. */
+/* --- new character v (118) starting at offset 0x055a --- */
+ /*055a:*/ 8, 6, 8, 1, 0, /* width and bbox (w,h,x,y) */
+ /*055f:*/ 0x84, /* #....#.. */
+ /*0560:*/ 0x84, /* #....#.. */
+ /*0561:*/ 0x84, /* #....#.. */
+ /*0562:*/ 0x48, /* .#..#... */
+ /*0563:*/ 0x48, /* .#..#... */
+ /*0564:*/ 0x48, /* .#..#... */
+ /*0565:*/ 0x30, /* ..##.... */
+ /*0566:*/ 0x30, /* ..##.... */
+/* --- new character w (119) starting at offset 0x0567 --- */
+ /*0567:*/ 10, 9, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*056c:*/ 0x88,0x80, /* #...#...#....... */
+ /*056e:*/ 0x88,0x80, /* #...#...#....... */
+ /*0570:*/ 0x88,0x80, /* #...#...#....... */
+ /*0572:*/ 0x49,0x00, /* .#..#..#........ */
+ /*0574:*/ 0x49,0x00, /* .#..#..#........ */
+ /*0576:*/ 0x55,0x00, /* .#.#.#.#........ */
+ /*0578:*/ 0x22,0x00, /* ..#...#......... */
+ /*057a:*/ 0x22,0x00, /* ..#...#......... */
+/* --- new character x (120) starting at offset 0x057c --- */
+ /*057c:*/ 7, 7, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0581:*/ 0xc6, /* ##...##. */
+ /*0582:*/ 0x44, /* .#...#.. */
+ /*0583:*/ 0x28, /* ..#.#... */
+ /*0584:*/ 0x10, /* ...#.... */
+ /*0585:*/ 0x10, /* ...#.... */
+ /*0586:*/ 0x28, /* ..#.#... */
+ /*0587:*/ 0x44, /* .#...#.. */
+ /*0588:*/ 0xc6, /* ##...##. */
+/* --- new character y (121) starting at offset 0x0589 --- */
+ /*0589:*/ 7, 7, 11, 0, -3, /* width and bbox (w,h,x,y) */
+ /*058e:*/ 0x82, /* #.....#. */
+ /*058f:*/ 0x82, /* #.....#. */
+ /*0590:*/ 0x44, /* .#...#.. */
+ /*0591:*/ 0x44, /* .#...#.. */
+ /*0592:*/ 0x24, /* ..#..#.. */
+ /*0593:*/ 0x28, /* ..#.#... */
+ /*0594:*/ 0x18, /* ...##... */
+ /*0595:*/ 0x10, /* ...#.... */
+ /*0596:*/ 0x10, /* ...#.... */
+ /*0597:*/ 0x30, /* ..##.... */
+ /*0598:*/ 0x60, /* .##..... */
+/* --- new character z (122) starting at offset 0x0599 --- */
+ /*0599:*/ 7, 6, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*059e:*/ 0xfc, /* ######.. */
+ /*059f:*/ 0x04, /* .....#.. */
+ /*05a0:*/ 0x08, /* ....#... */
+ /*05a1:*/ 0x10, /* ...#.... */
+ /*05a2:*/ 0x20, /* ..#..... */
+ /*05a3:*/ 0x40, /* .#...... */
+ /*05a4:*/ 0x80, /* #....... */
+ /*05a5:*/ 0xfc, /* ######.. */
+/* --- new character braceleft (123) starting at offset 0x05a6 --- */
+ /*05a6:*/ 5, 5, 14, 0, -3, /* width and bbox (w,h,x,y) */
+ /*05ab:*/ 0x18, /* ...##... */
+ /*05ac:*/ 0x20, /* ..#..... */
+ /*05ad:*/ 0x20, /* ..#..... */
+ /*05ae:*/ 0x20, /* ..#..... */
+ /*05af:*/ 0x20, /* ..#..... */
+ /*05b0:*/ 0x40, /* .#...... */
+ /*05b1:*/ 0x80, /* #....... */
+ /*05b2:*/ 0x40, /* .#...... */
+ /*05b3:*/ 0x20, /* ..#..... */
+ /*05b4:*/ 0x20, /* ..#..... */
+ /*05b5:*/ 0x20, /* ..#..... */
+ /*05b6:*/ 0x20, /* ..#..... */
+ /*05b7:*/ 0x20, /* ..#..... */
+ /*05b8:*/ 0x18, /* ...##... */
+/* --- new character bar (124) starting at offset 0x05b9 --- */
+ /*05b9:*/ 3, 1, 14, 1, -3, /* width and bbox (w,h,x,y) */
+ /*05be:*/ 0x80, /* #....... */
+ /*05bf:*/ 0x80, /* #....... */
+ /*05c0:*/ 0x80, /* #....... */
+ /*05c1:*/ 0x80, /* #....... */
+ /*05c2:*/ 0x80, /* #....... */
+ /*05c3:*/ 0x80, /* #....... */
+ /*05c4:*/ 0x80, /* #....... */
+ /*05c5:*/ 0x80, /* #....... */
+ /*05c6:*/ 0x80, /* #....... */
+ /*05c7:*/ 0x80, /* #....... */
+ /*05c8:*/ 0x80, /* #....... */
+ /*05c9:*/ 0x80, /* #....... */
+ /*05ca:*/ 0x80, /* #....... */
+ /*05cb:*/ 0x80, /* #....... */
+/* --- new character braceright (125) starting at offset 0x05cc --- */
+ /*05cc:*/ 5, 5, 14, 0, -3, /* width and bbox (w,h,x,y) */
+ /*05d1:*/ 0xc0, /* ##...... */
+ /*05d2:*/ 0x20, /* ..#..... */
+ /*05d3:*/ 0x20, /* ..#..... */
+ /*05d4:*/ 0x20, /* ..#..... */
+ /*05d5:*/ 0x20, /* ..#..... */
+ /*05d6:*/ 0x10, /* ...#.... */
+ /*05d7:*/ 0x08, /* ....#... */
+ /*05d8:*/ 0x10, /* ...#.... */
+ /*05d9:*/ 0x20, /* ..#..... */
+ /*05da:*/ 0x20, /* ..#..... */
+ /*05db:*/ 0x20, /* ..#..... */
+ /*05dc:*/ 0x20, /* ..#..... */
+ /*05dd:*/ 0x20, /* ..#..... */
+ /*05de:*/ 0xc0, /* ##...... */
+/* --- new character asciitilde (126) starting at offset 0x05df --- */
+ /*05df:*/ 8, 6, 3, 1, 3, /* width and bbox (w,h,x,y) */
+ /*05e4:*/ 0x64, /* .##..#.. */
+ /*05e5:*/ 0xb4, /* #.##.#.. */
+ /*05e6:*/ 0x98, /* #..##... */
+};
+static const uint16_t font_helvR14_offsets[] = {
+0x0000 /* space */,
+ 0x0006 /* exclam */,
+ 0x0016 /* quotedbl */,
+ 0x001e /* numbersign */,
+ 0x002d /* dollar */,
+ 0x0040 /* percent */,
+ 0x0059 /* ampersand */,
+ 0x0068 /* quotesingle */,
+ 0x0070 /* parenleft */,
+ 0x0083 /* parenright */,
+ 0x0096 /* asterisk */,
+ 0x009f /* plus */,
+ 0x00ab /* comma */,
+ 0x00b4 /* hyphen */,
+ 0x00ba /* period */,
+ 0x00c1 /* slash */,
+ 0x00d1 /* zero */,
+ 0x00e0 /* one */,
+ 0x00ef /* two */,
+ 0x00fe /* three */,
+ 0x010d /* four */,
+ 0x011c /* five */,
+ 0x012b /* six */,
+ 0x013a /* seven */,
+ 0x0149 /* eight */,
+ 0x0158 /* nine */,
+ 0x0167 /* colon */,
+ 0x0174 /* semicolon */,
+ 0x0183 /* less */,
+ 0x018d /* equal */,
+ 0x0195 /* greater */,
+ 0x019f /* question */,
+ 0x01af /* at */,
+ 0x01cc /* A */,
+ 0x01e7 /* B */,
+ 0x01f7 /* C */,
+ 0x0207 /* D */,
+ 0x0217 /* E */,
+ 0x0227 /* F */,
+ 0x0237 /* G */,
+ 0x0252 /* H */,
+ 0x0262 /* I */,
+ 0x0272 /* J */,
+ 0x0282 /* K */,
+ 0x0292 /* L */,
+ 0x02a2 /* M */,
+ 0x02bd /* N */,
+ 0x02cd /* O */,
+ 0x02e8 /* P */,
+ 0x02f8 /* Q */,
+ 0x0313 /* R */,
+ 0x0323 /* S */,
+ 0x0333 /* T */,
+ 0x034e /* U */,
+ 0x035e /* V */,
+ 0x0379 /* W */,
+ 0x0394 /* X */,
+ 0x03a4 /* Y */,
+ 0x03bf /* Z */,
+ 0x03cf /* bracketleft */,
+ 0x03e2 /* backslash */,
+ 0x03f2 /* bracketright */,
+ 0x0405 /* asciicircum */,
+ 0x040e /* underscore */,
+ 0x0414 /* grave */,
+ 0x041b /* a */,
+ 0x0428 /* b */,
+ 0x0438 /* c */,
+ 0x0445 /* d */,
+ 0x0455 /* e */,
+ 0x0462 /* f */,
+ 0x0472 /* g */,
+ 0x0482 /* h */,
+ 0x0492 /* i */,
+ 0x04a2 /* j */,
+ 0x04b5 /* k */,
+ 0x04c5 /* l */,
+ 0x04d5 /* m */,
+ 0x04ea /* n */,
+ 0x04f7 /* o */,
+ 0x0504 /* p */,
+ 0x0514 /* q */,
+ 0x0524 /* r */,
+ 0x0531 /* s */,
+ 0x053e /* t */,
+ 0x054d /* u */,
+ 0x055a /* v */,
+ 0x0567 /* w */,
+ 0x057c /* x */,
+ 0x0589 /* y */,
+ 0x0599 /* z */,
+ 0x05a6 /* braceleft */,
+ 0x05b9 /* bar */,
+ 0x05cc /* braceright */,
+ 0x05df /* asciitilde */,
+ 0xffff /* (no glyph) */
+};
+const struct fb_font font_helvR14 = {
+ .height = 16,
+ .ascent = 13,
+ .firstchar = 32, /* space */
+ .lastchar = 127, /* ? */
+ .chardata = font_helvR14_data,
+ .charoffs = font_helvR14_offsets,
+};
diff --git a/src/target/firmware/fb/helvR24.c b/src/target/firmware/fb/helvR24.c
new file mode 100644
index 00000000..18ff0c40
--- /dev/null
+++ b/src/target/firmware/fb/helvR24.c
@@ -0,0 +1,1870 @@
+#include <fb/font.h>
+static const uint8_t font_helvR24_data[] = {
+/* --- new character space (32) starting at offset 0x0000 --- */
+ /*0000:*/ 6, 1, 1, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x00, /* ........ */
+/* --- new character exclam (33) starting at offset 0x0006 --- */
+ /*0006:*/ 6, 2, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*000b:*/ 0xc0, /* ##...... */
+ /*000c:*/ 0xc0, /* ##...... */
+ /*000d:*/ 0xc0, /* ##...... */
+ /*000e:*/ 0xc0, /* ##...... */
+ /*000f:*/ 0xc0, /* ##...... */
+ /*0010:*/ 0xc0, /* ##...... */
+ /*0011:*/ 0xc0, /* ##...... */
+ /*0012:*/ 0xc0, /* ##...... */
+ /*0013:*/ 0xc0, /* ##...... */
+ /*0014:*/ 0xc0, /* ##...... */
+ /*0015:*/ 0xc0, /* ##...... */
+ /*0016:*/ 0xc0, /* ##...... */
+ /*0017:*/ 0x80, /* #....... */
+ /*0018:*/ 0x80, /* #....... */
+ /*0019:*/ 0x00, /* ........ */
+ /*001a:*/ 0x00, /* ........ */
+ /*001b:*/ 0xc0, /* ##...... */
+ /*001c:*/ 0xc0, /* ##...... */
+ /*001d:*/ 0xc0, /* ##...... */
+/* --- new character quotedbl (34) starting at offset 0x001e --- */
+ /*001e:*/ 8, 6, 6, 1, 13, /* width and bbox (w,h,x,y) */
+ /*0023:*/ 0xcc, /* ##..##.. */
+ /*0024:*/ 0xcc, /* ##..##.. */
+ /*0025:*/ 0xcc, /* ##..##.. */
+ /*0026:*/ 0xcc, /* ##..##.. */
+ /*0027:*/ 0xcc, /* ##..##.. */
+ /*0028:*/ 0x44, /* .#...#.. */
+/* --- new character numbersign (35) starting at offset 0x0029 --- */
+ /*0029:*/ 14, 11, 17, 2, 0, /* width and bbox (w,h,x,y) */
+ /*002e:*/ 0x0c,0xc0, /* ....##..##...... */
+ /*0030:*/ 0x0c,0xc0, /* ....##..##...... */
+ /*0032:*/ 0x0c,0xc0, /* ....##..##...... */
+ /*0034:*/ 0x19,0x80, /* ...##..##....... */
+ /*0036:*/ 0xff,0xe0, /* ###########..... */
+ /*0038:*/ 0xff,0xe0, /* ###########..... */
+ /*003a:*/ 0x19,0x80, /* ...##..##....... */
+ /*003c:*/ 0x19,0x80, /* ...##..##....... */
+ /*003e:*/ 0x33,0x00, /* ..##..##........ */
+ /*0040:*/ 0x33,0x00, /* ..##..##........ */
+ /*0042:*/ 0xff,0xe0, /* ###########..... */
+ /*0044:*/ 0xff,0xe0, /* ###########..... */
+ /*0046:*/ 0x33,0x00, /* ..##..##........ */
+ /*0048:*/ 0x33,0x00, /* ..##..##........ */
+ /*004a:*/ 0x66,0x00, /* .##..##......... */
+ /*004c:*/ 0x66,0x00, /* .##..##......... */
+ /*004e:*/ 0x66,0x00, /* .##..##......... */
+/* --- new character dollar (36) starting at offset 0x0050 --- */
+ /*0050:*/ 13, 11, 21, 1, -2, /* width and bbox (w,h,x,y) */
+ /*0055:*/ 0x06,0x00, /* .....##......... */
+ /*0057:*/ 0x06,0x00, /* .....##......... */
+ /*0059:*/ 0x3f,0x80, /* ..#######....... */
+ /*005b:*/ 0x7f,0xc0, /* .#########...... */
+ /*005d:*/ 0xe6,0xe0, /* ###..##.###..... */
+ /*005f:*/ 0xc6,0x60, /* ##...##..##..... */
+ /*0061:*/ 0xc6,0x00, /* ##...##......... */
+ /*0063:*/ 0xe6,0x00, /* ###..##......... */
+ /*0065:*/ 0x76,0x00, /* .###.##......... */
+ /*0067:*/ 0x3e,0x00, /* ..#####......... */
+ /*0069:*/ 0x0f,0x80, /* ....#####....... */
+ /*006b:*/ 0x07,0xc0, /* .....#####...... */
+ /*006d:*/ 0x06,0xe0, /* .....##.###..... */
+ /*006f:*/ 0x06,0x60, /* .....##..##..... */
+ /*0071:*/ 0xc6,0x60, /* ##...##..##..... */
+ /*0073:*/ 0xc6,0x60, /* ##...##..##..... */
+ /*0075:*/ 0xe6,0xe0, /* ###..##.###..... */
+ /*0077:*/ 0x7f,0xc0, /* .#########...... */
+ /*0079:*/ 0x3f,0x80, /* ..#######....... */
+ /*007b:*/ 0x06,0x00, /* .....##......... */
+ /*007d:*/ 0x06,0x00, /* .....##......... */
+/* --- new character percent (37) starting at offset 0x007f --- */
+ /*007f:*/ 22, 19, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0084:*/ 0x00,0x06,0x00, /* .............##......... */
+ /*0087:*/ 0x3c,0x0c,0x00, /* ..####......##.......... */
+ /*008a:*/ 0x7e,0x0c,0x00, /* .######.....##.......... */
+ /*008d:*/ 0xc3,0x18,0x00, /* ##....##...##........... */
+ /*0090:*/ 0xc3,0x18,0x00, /* ##....##...##........... */
+ /*0093:*/ 0xc3,0x30,0x00, /* ##....##..##............ */
+ /*0096:*/ 0xc3,0x30,0x00, /* ##....##..##............ */
+ /*0099:*/ 0x7e,0x60,0x00, /* .######..##............. */
+ /*009c:*/ 0x3c,0x60,0x00, /* ..####...##............. */
+ /*009f:*/ 0x00,0xc0,0x00, /* ........##.............. */
+ /*00a2:*/ 0x00,0xc7,0x80, /* ........##...####....... */
+ /*00a5:*/ 0x01,0x8f,0xc0, /* .......##...######...... */
+ /*00a8:*/ 0x01,0x98,0x60, /* .......##..##....##..... */
+ /*00ab:*/ 0x03,0x18,0x60, /* ......##...##....##..... */
+ /*00ae:*/ 0x03,0x18,0x60, /* ......##...##....##..... */
+ /*00b1:*/ 0x06,0x18,0x60, /* .....##....##....##..... */
+ /*00b4:*/ 0x06,0x0f,0xc0, /* .....##.....######...... */
+ /*00b7:*/ 0x04,0x07,0x80, /* .....#.......####....... */
+/* --- new character ampersand (38) starting at offset 0x00ba --- */
+ /*00ba:*/ 17, 14, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*00bf:*/ 0x0f,0x00, /* ....####........ */
+ /*00c1:*/ 0x1f,0x80, /* ...######....... */
+ /*00c3:*/ 0x39,0xc0, /* ..###..###...... */
+ /*00c5:*/ 0x30,0xc0, /* ..##....##...... */
+ /*00c7:*/ 0x30,0xc0, /* ..##....##...... */
+ /*00c9:*/ 0x30,0xc0, /* ..##....##...... */
+ /*00cb:*/ 0x19,0x80, /* ...##..##....... */
+ /*00cd:*/ 0x0f,0x00, /* ....####........ */
+ /*00cf:*/ 0x1e,0x00, /* ...####......... */
+ /*00d1:*/ 0x3f,0x18, /* ..######...##... */
+ /*00d3:*/ 0x73,0x98, /* .###..###..##... */
+ /*00d5:*/ 0x61,0xd8, /* .##....###.##... */
+ /*00d7:*/ 0xc0,0xf0, /* ##......####.... */
+ /*00d9:*/ 0xc0,0x60, /* ##.......##..... */
+ /*00db:*/ 0xc0,0xf0, /* ##......####.... */
+ /*00dd:*/ 0xe1,0xd8, /* ###....###.##... */
+ /*00df:*/ 0x7f,0x9c, /* .########..###.. */
+ /*00e1:*/ 0x1e,0x00, /* ...####......... */
+/* --- new character quotesingle (39) starting at offset 0x00e3 --- */
+ /*00e3:*/ 6, 2, 6, 2, 13, /* width and bbox (w,h,x,y) */
+ /*00e8:*/ 0xc0, /* ##...... */
+ /*00e9:*/ 0xc0, /* ##...... */
+ /*00ea:*/ 0xc0, /* ##...... */
+ /*00eb:*/ 0xc0, /* ##...... */
+ /*00ec:*/ 0xc0, /* ##...... */
+ /*00ed:*/ 0x40, /* .#...... */
+/* --- new character parenleft (40) starting at offset 0x00ee --- */
+ /*00ee:*/ 8, 5, 24, 2, -5, /* width and bbox (w,h,x,y) */
+ /*00f3:*/ 0x18, /* ...##... */
+ /*00f4:*/ 0x18, /* ...##... */
+ /*00f5:*/ 0x30, /* ..##.... */
+ /*00f6:*/ 0x30, /* ..##.... */
+ /*00f7:*/ 0x60, /* .##..... */
+ /*00f8:*/ 0x60, /* .##..... */
+ /*00f9:*/ 0x60, /* .##..... */
+ /*00fa:*/ 0xc0, /* ##...... */
+ /*00fb:*/ 0xc0, /* ##...... */
+ /*00fc:*/ 0xc0, /* ##...... */
+ /*00fd:*/ 0xc0, /* ##...... */
+ /*00fe:*/ 0xc0, /* ##...... */
+ /*00ff:*/ 0xc0, /* ##...... */
+ /*0100:*/ 0xc0, /* ##...... */
+ /*0101:*/ 0xc0, /* ##...... */
+ /*0102:*/ 0xc0, /* ##...... */
+ /*0103:*/ 0xc0, /* ##...... */
+ /*0104:*/ 0x60, /* .##..... */
+ /*0105:*/ 0x60, /* .##..... */
+ /*0106:*/ 0x60, /* .##..... */
+ /*0107:*/ 0x30, /* ..##.... */
+ /*0108:*/ 0x30, /* ..##.... */
+ /*0109:*/ 0x18, /* ...##... */
+ /*010a:*/ 0x18, /* ...##... */
+/* --- new character parenright (41) starting at offset 0x010b --- */
+ /*010b:*/ 8, 5, 24, 1, -5, /* width and bbox (w,h,x,y) */
+ /*0110:*/ 0xc0, /* ##...... */
+ /*0111:*/ 0xc0, /* ##...... */
+ /*0112:*/ 0x60, /* .##..... */
+ /*0113:*/ 0x60, /* .##..... */
+ /*0114:*/ 0x30, /* ..##.... */
+ /*0115:*/ 0x30, /* ..##.... */
+ /*0116:*/ 0x30, /* ..##.... */
+ /*0117:*/ 0x18, /* ...##... */
+ /*0118:*/ 0x18, /* ...##... */
+ /*0119:*/ 0x18, /* ...##... */
+ /*011a:*/ 0x18, /* ...##... */
+ /*011b:*/ 0x18, /* ...##... */
+ /*011c:*/ 0x18, /* ...##... */
+ /*011d:*/ 0x18, /* ...##... */
+ /*011e:*/ 0x18, /* ...##... */
+ /*011f:*/ 0x18, /* ...##... */
+ /*0120:*/ 0x18, /* ...##... */
+ /*0121:*/ 0x30, /* ..##.... */
+ /*0122:*/ 0x30, /* ..##.... */
+ /*0123:*/ 0x30, /* ..##.... */
+ /*0124:*/ 0x60, /* .##..... */
+ /*0125:*/ 0x60, /* .##..... */
+ /*0126:*/ 0xc0, /* ##...... */
+ /*0127:*/ 0xc0, /* ##...... */
+/* --- new character asterisk (42) starting at offset 0x0128 --- */
+ /*0128:*/ 10, 7, 7, 1, 12, /* width and bbox (w,h,x,y) */
+ /*012d:*/ 0x10, /* ...#.... */
+ /*012e:*/ 0x10, /* ...#.... */
+ /*012f:*/ 0xd6, /* ##.#.##. */
+ /*0130:*/ 0x7c, /* .#####.. */
+ /*0131:*/ 0x38, /* ..###... */
+ /*0132:*/ 0x6c, /* .##.##.. */
+ /*0133:*/ 0x44, /* .#...#.. */
+/* --- new character plus (43) starting at offset 0x0134 --- */
+ /*0134:*/ 14, 12, 12, 1, 1, /* width and bbox (w,h,x,y) */
+ /*0139:*/ 0x06,0x00, /* .....##......... */
+ /*013b:*/ 0x06,0x00, /* .....##......... */
+ /*013d:*/ 0x06,0x00, /* .....##......... */
+ /*013f:*/ 0x06,0x00, /* .....##......... */
+ /*0141:*/ 0x06,0x00, /* .....##......... */
+ /*0143:*/ 0xff,0xf0, /* ############.... */
+ /*0145:*/ 0xff,0xf0, /* ############.... */
+ /*0147:*/ 0x06,0x00, /* .....##......... */
+ /*0149:*/ 0x06,0x00, /* .....##......... */
+ /*014b:*/ 0x06,0x00, /* .....##......... */
+ /*014d:*/ 0x06,0x00, /* .....##......... */
+ /*014f:*/ 0x06,0x00, /* .....##......... */
+/* --- new character comma (44) starting at offset 0x0151 --- */
+ /*0151:*/ 6, 2, 6, 2, -3, /* width and bbox (w,h,x,y) */
+ /*0156:*/ 0xc0, /* ##...... */
+ /*0157:*/ 0xc0, /* ##...... */
+ /*0158:*/ 0xc0, /* ##...... */
+ /*0159:*/ 0x40, /* .#...... */
+ /*015a:*/ 0x40, /* .#...... */
+ /*015b:*/ 0x80, /* #....... */
+/* --- new character hyphen (45) starting at offset 0x015c --- */
+ /*015c:*/ 8, 6, 2, 1, 6, /* width and bbox (w,h,x,y) */
+ /*0161:*/ 0xfc, /* ######.. */
+ /*0162:*/ 0xfc, /* ######.. */
+/* --- new character period (46) starting at offset 0x0163 --- */
+ /*0163:*/ 6, 2, 3, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0168:*/ 0xc0, /* ##...... */
+ /*0169:*/ 0xc0, /* ##...... */
+ /*016a:*/ 0xc0, /* ##...... */
+/* --- new character slash (47) starting at offset 0x016b --- */
+ /*016b:*/ 7, 7, 19, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0170:*/ 0x06, /* .....##. */
+ /*0171:*/ 0x06, /* .....##. */
+ /*0172:*/ 0x06, /* .....##. */
+ /*0173:*/ 0x0c, /* ....##.. */
+ /*0174:*/ 0x0c, /* ....##.. */
+ /*0175:*/ 0x0c, /* ....##.. */
+ /*0176:*/ 0x18, /* ...##... */
+ /*0177:*/ 0x18, /* ...##... */
+ /*0178:*/ 0x18, /* ...##... */
+ /*0179:*/ 0x18, /* ...##... */
+ /*017a:*/ 0x30, /* ..##.... */
+ /*017b:*/ 0x30, /* ..##.... */
+ /*017c:*/ 0x30, /* ..##.... */
+ /*017d:*/ 0x60, /* .##..... */
+ /*017e:*/ 0x60, /* .##..... */
+ /*017f:*/ 0x60, /* .##..... */
+ /*0180:*/ 0xc0, /* ##...... */
+ /*0181:*/ 0xc0, /* ##...... */
+ /*0182:*/ 0xc0, /* ##...... */
+/* --- new character zero (48) starting at offset 0x0183 --- */
+ /*0183:*/ 13, 11, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0188:*/ 0x1f,0x00, /* ...#####........ */
+ /*018a:*/ 0x3f,0x80, /* ..#######....... */
+ /*018c:*/ 0x71,0xc0, /* .###...###...... */
+ /*018e:*/ 0x60,0xc0, /* .##.....##...... */
+ /*0190:*/ 0x60,0xc0, /* .##.....##...... */
+ /*0192:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0194:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0196:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0198:*/ 0xc0,0x60, /* ##.......##..... */
+ /*019a:*/ 0xc0,0x60, /* ##.......##..... */
+ /*019c:*/ 0xc0,0x60, /* ##.......##..... */
+ /*019e:*/ 0xc0,0x60, /* ##.......##..... */
+ /*01a0:*/ 0xc0,0x60, /* ##.......##..... */
+ /*01a2:*/ 0x60,0xc0, /* .##.....##...... */
+ /*01a4:*/ 0x60,0xc0, /* .##.....##...... */
+ /*01a6:*/ 0x71,0xc0, /* .###...###...... */
+ /*01a8:*/ 0x3f,0x80, /* ..#######....... */
+ /*01aa:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character one (49) starting at offset 0x01ac --- */
+ /*01ac:*/ 13, 6, 18, 2, 0, /* width and bbox (w,h,x,y) */
+ /*01b1:*/ 0x0c, /* ....##.. */
+ /*01b2:*/ 0x0c, /* ....##.. */
+ /*01b3:*/ 0x1c, /* ...###.. */
+ /*01b4:*/ 0xfc, /* ######.. */
+ /*01b5:*/ 0xfc, /* ######.. */
+ /*01b6:*/ 0x0c, /* ....##.. */
+ /*01b7:*/ 0x0c, /* ....##.. */
+ /*01b8:*/ 0x0c, /* ....##.. */
+ /*01b9:*/ 0x0c, /* ....##.. */
+ /*01ba:*/ 0x0c, /* ....##.. */
+ /*01bb:*/ 0x0c, /* ....##.. */
+ /*01bc:*/ 0x0c, /* ....##.. */
+ /*01bd:*/ 0x0c, /* ....##.. */
+ /*01be:*/ 0x0c, /* ....##.. */
+ /*01bf:*/ 0x0c, /* ....##.. */
+ /*01c0:*/ 0x0c, /* ....##.. */
+ /*01c1:*/ 0x0c, /* ....##.. */
+ /*01c2:*/ 0x0c, /* ....##.. */
+/* --- new character two (50) starting at offset 0x01c3 --- */
+ /*01c3:*/ 13, 11, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01c8:*/ 0x1e,0x00, /* ...####......... */
+ /*01ca:*/ 0x7f,0x80, /* .########....... */
+ /*01cc:*/ 0x61,0xc0, /* .##....###...... */
+ /*01ce:*/ 0xc0,0xc0, /* ##......##...... */
+ /*01d0:*/ 0xc0,0x60, /* ##.......##..... */
+ /*01d2:*/ 0xc0,0x60, /* ##.......##..... */
+ /*01d4:*/ 0x00,0x60, /* .........##..... */
+ /*01d6:*/ 0x00,0xc0, /* ........##...... */
+ /*01d8:*/ 0x01,0xc0, /* .......###...... */
+ /*01da:*/ 0x03,0x80, /* ......###....... */
+ /*01dc:*/ 0x0f,0x00, /* ....####........ */
+ /*01de:*/ 0x1c,0x00, /* ...###.......... */
+ /*01e0:*/ 0x38,0x00, /* ..###........... */
+ /*01e2:*/ 0x70,0x00, /* .###............ */
+ /*01e4:*/ 0xe0,0x00, /* ###............. */
+ /*01e6:*/ 0xc0,0x00, /* ##.............. */
+ /*01e8:*/ 0xff,0xe0, /* ###########..... */
+ /*01ea:*/ 0xff,0xe0, /* ###########..... */
+/* --- new character three (51) starting at offset 0x01ec --- */
+ /*01ec:*/ 13, 11, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*01f1:*/ 0x1f,0x00, /* ...#####........ */
+ /*01f3:*/ 0x7f,0x80, /* .########....... */
+ /*01f5:*/ 0x61,0x80, /* .##....##....... */
+ /*01f7:*/ 0xc0,0xc0, /* ##......##...... */
+ /*01f9:*/ 0xc0,0xc0, /* ##......##...... */
+ /*01fb:*/ 0xc0,0xc0, /* ##......##...... */
+ /*01fd:*/ 0x00,0xc0, /* ........##...... */
+ /*01ff:*/ 0x01,0x80, /* .......##....... */
+ /*0201:*/ 0x0f,0x00, /* ....####........ */
+ /*0203:*/ 0x0f,0xc0, /* ....######...... */
+ /*0205:*/ 0x00,0xc0, /* ........##...... */
+ /*0207:*/ 0x00,0x60, /* .........##..... */
+ /*0209:*/ 0x00,0x60, /* .........##..... */
+ /*020b:*/ 0xc0,0x60, /* ##.......##..... */
+ /*020d:*/ 0xc0,0xc0, /* ##......##...... */
+ /*020f:*/ 0x61,0xc0, /* .##....###...... */
+ /*0211:*/ 0x7f,0x80, /* .########....... */
+ /*0213:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character four (52) starting at offset 0x0215 --- */
+ /*0215:*/ 13, 11, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*021a:*/ 0x01,0x80, /* .......##....... */
+ /*021c:*/ 0x03,0x80, /* ......###....... */
+ /*021e:*/ 0x03,0x80, /* ......###....... */
+ /*0220:*/ 0x07,0x80, /* .....####....... */
+ /*0222:*/ 0x0f,0x80, /* ....#####....... */
+ /*0224:*/ 0x0d,0x80, /* ....##.##....... */
+ /*0226:*/ 0x19,0x80, /* ...##..##....... */
+ /*0228:*/ 0x39,0x80, /* ..###..##....... */
+ /*022a:*/ 0x31,0x80, /* ..##...##....... */
+ /*022c:*/ 0x61,0x80, /* .##....##....... */
+ /*022e:*/ 0xe1,0x80, /* ###....##....... */
+ /*0230:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0232:*/ 0xff,0xe0, /* ###########..... */
+ /*0234:*/ 0xff,0xe0, /* ###########..... */
+ /*0236:*/ 0x01,0x80, /* .......##....... */
+ /*0238:*/ 0x01,0x80, /* .......##....... */
+ /*023a:*/ 0x01,0x80, /* .......##....... */
+ /*023c:*/ 0x01,0x80, /* .......##....... */
+/* --- new character five (53) starting at offset 0x023e --- */
+ /*023e:*/ 13, 11, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0243:*/ 0x7f,0xc0, /* .#########...... */
+ /*0245:*/ 0x7f,0xc0, /* .#########...... */
+ /*0247:*/ 0x60,0x00, /* .##............. */
+ /*0249:*/ 0x60,0x00, /* .##............. */
+ /*024b:*/ 0x60,0x00, /* .##............. */
+ /*024d:*/ 0x60,0x00, /* .##............. */
+ /*024f:*/ 0x6e,0x00, /* .##.###......... */
+ /*0251:*/ 0x7f,0x80, /* .########....... */
+ /*0253:*/ 0x71,0xc0, /* .###...###...... */
+ /*0255:*/ 0x00,0xc0, /* ........##...... */
+ /*0257:*/ 0x00,0x60, /* .........##..... */
+ /*0259:*/ 0x00,0x60, /* .........##..... */
+ /*025b:*/ 0x00,0x60, /* .........##..... */
+ /*025d:*/ 0xc0,0x60, /* ##.......##..... */
+ /*025f:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0261:*/ 0xe1,0xc0, /* ###....###...... */
+ /*0263:*/ 0x7f,0x80, /* .########....... */
+ /*0265:*/ 0x1e,0x00, /* ...####......... */
+/* --- new character six (54) starting at offset 0x0267 --- */
+ /*0267:*/ 13, 11, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*026c:*/ 0x0f,0x00, /* ....####........ */
+ /*026e:*/ 0x3f,0xc0, /* ..########...... */
+ /*0270:*/ 0x70,0xc0, /* .###....##...... */
+ /*0272:*/ 0x60,0x60, /* .##......##..... */
+ /*0274:*/ 0xe0,0x60, /* ###......##..... */
+ /*0276:*/ 0xc0,0x00, /* ##.............. */
+ /*0278:*/ 0xc0,0x00, /* ##.............. */
+ /*027a:*/ 0xcf,0x00, /* ##..####........ */
+ /*027c:*/ 0xdf,0x80, /* ##.######....... */
+ /*027e:*/ 0xf1,0xc0, /* ####...###...... */
+ /*0280:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*0282:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0284:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0286:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0288:*/ 0xe0,0x60, /* ###......##..... */
+ /*028a:*/ 0x60,0xc0, /* .##.....##...... */
+ /*028c:*/ 0x7f,0xc0, /* .#########...... */
+ /*028e:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character seven (55) starting at offset 0x0290 --- */
+ /*0290:*/ 13, 11, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0295:*/ 0xff,0xe0, /* ###########..... */
+ /*0297:*/ 0xff,0xe0, /* ###########..... */
+ /*0299:*/ 0x00,0xe0, /* ........###..... */
+ /*029b:*/ 0x00,0xc0, /* ........##...... */
+ /*029d:*/ 0x01,0x80, /* .......##....... */
+ /*029f:*/ 0x01,0x80, /* .......##....... */
+ /*02a1:*/ 0x03,0x00, /* ......##........ */
+ /*02a3:*/ 0x03,0x00, /* ......##........ */
+ /*02a5:*/ 0x06,0x00, /* .....##......... */
+ /*02a7:*/ 0x06,0x00, /* .....##......... */
+ /*02a9:*/ 0x0c,0x00, /* ....##.......... */
+ /*02ab:*/ 0x0c,0x00, /* ....##.......... */
+ /*02ad:*/ 0x1c,0x00, /* ...###.......... */
+ /*02af:*/ 0x18,0x00, /* ...##........... */
+ /*02b1:*/ 0x18,0x00, /* ...##........... */
+ /*02b3:*/ 0x38,0x00, /* ..###........... */
+ /*02b5:*/ 0x30,0x00, /* ..##............ */
+ /*02b7:*/ 0x30,0x00, /* ..##............ */
+/* --- new character eight (56) starting at offset 0x02b9 --- */
+ /*02b9:*/ 13, 11, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02be:*/ 0x0e,0x00, /* ....###......... */
+ /*02c0:*/ 0x3f,0x80, /* ..#######....... */
+ /*02c2:*/ 0x31,0x80, /* ..##...##....... */
+ /*02c4:*/ 0x60,0xc0, /* .##.....##...... */
+ /*02c6:*/ 0x60,0xc0, /* .##.....##...... */
+ /*02c8:*/ 0x60,0xc0, /* .##.....##...... */
+ /*02ca:*/ 0x60,0xc0, /* .##.....##...... */
+ /*02cc:*/ 0x31,0x80, /* ..##...##....... */
+ /*02ce:*/ 0x1f,0x00, /* ...#####........ */
+ /*02d0:*/ 0x3f,0x80, /* ..#######....... */
+ /*02d2:*/ 0x60,0xc0, /* .##.....##...... */
+ /*02d4:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*02d6:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02d8:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02da:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02dc:*/ 0x71,0xc0, /* .###...###...... */
+ /*02de:*/ 0x7f,0xc0, /* .#########...... */
+ /*02e0:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character nine (57) starting at offset 0x02e2 --- */
+ /*02e2:*/ 13, 11, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*02e7:*/ 0x1f,0x00, /* ...#####........ */
+ /*02e9:*/ 0x7f,0xc0, /* .#########...... */
+ /*02eb:*/ 0x71,0xc0, /* .###...###...... */
+ /*02ed:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*02ef:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02f1:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02f3:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02f5:*/ 0xc0,0x60, /* ##.......##..... */
+ /*02f7:*/ 0xe0,0xe0, /* ###.....###..... */
+ /*02f9:*/ 0x71,0xe0, /* .###...####..... */
+ /*02fb:*/ 0x7f,0x60, /* .#######.##..... */
+ /*02fd:*/ 0x1e,0x60, /* ...####..##..... */
+ /*02ff:*/ 0x00,0x60, /* .........##..... */
+ /*0301:*/ 0x00,0xe0, /* ........###..... */
+ /*0303:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0305:*/ 0xe1,0xc0, /* ###....###...... */
+ /*0307:*/ 0x7f,0x80, /* .########....... */
+ /*0309:*/ 0x1e,0x00, /* ...####......... */
+/* --- new character colon (58) starting at offset 0x030b --- */
+ /*030b:*/ 6, 2, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0310:*/ 0xc0, /* ##...... */
+ /*0311:*/ 0xc0, /* ##...... */
+ /*0312:*/ 0xc0, /* ##...... */
+ /*0313:*/ 0x00, /* ........ */
+ /*0314:*/ 0x00, /* ........ */
+ /*0315:*/ 0x00, /* ........ */
+ /*0316:*/ 0x00, /* ........ */
+ /*0317:*/ 0x00, /* ........ */
+ /*0318:*/ 0x00, /* ........ */
+ /*0319:*/ 0x00, /* ........ */
+ /*031a:*/ 0x00, /* ........ */
+ /*031b:*/ 0xc0, /* ##...... */
+ /*031c:*/ 0xc0, /* ##...... */
+ /*031d:*/ 0xc0, /* ##...... */
+/* --- new character semicolon (59) starting at offset 0x031e --- */
+ /*031e:*/ 6, 2, 17, 2, -3, /* width and bbox (w,h,x,y) */
+ /*0323:*/ 0xc0, /* ##...... */
+ /*0324:*/ 0xc0, /* ##...... */
+ /*0325:*/ 0xc0, /* ##...... */
+ /*0326:*/ 0x00, /* ........ */
+ /*0327:*/ 0x00, /* ........ */
+ /*0328:*/ 0x00, /* ........ */
+ /*0329:*/ 0x00, /* ........ */
+ /*032a:*/ 0x00, /* ........ */
+ /*032b:*/ 0x00, /* ........ */
+ /*032c:*/ 0x00, /* ........ */
+ /*032d:*/ 0x00, /* ........ */
+ /*032e:*/ 0xc0, /* ##...... */
+ /*032f:*/ 0xc0, /* ##...... */
+ /*0330:*/ 0xc0, /* ##...... */
+ /*0331:*/ 0x40, /* .#...... */
+ /*0332:*/ 0x40, /* .#...... */
+ /*0333:*/ 0x80, /* #....... */
+/* --- new character less (60) starting at offset 0x0334 --- */
+ /*0334:*/ 15, 12, 12, 1, 1, /* width and bbox (w,h,x,y) */
+ /*0339:*/ 0x00,0x30, /* ..........##.... */
+ /*033b:*/ 0x00,0xf0, /* ........####.... */
+ /*033d:*/ 0x03,0xc0, /* ......####...... */
+ /*033f:*/ 0x0f,0x00, /* ....####........ */
+ /*0341:*/ 0x3c,0x00, /* ..####.......... */
+ /*0343:*/ 0xe0,0x00, /* ###............. */
+ /*0345:*/ 0xe0,0x00, /* ###............. */
+ /*0347:*/ 0x3c,0x00, /* ..####.......... */
+ /*0349:*/ 0x0f,0x00, /* ....####........ */
+ /*034b:*/ 0x03,0xc0, /* ......####...... */
+ /*034d:*/ 0x00,0xf0, /* ........####.... */
+ /*034f:*/ 0x00,0x30, /* ..........##.... */
+/* --- new character equal (61) starting at offset 0x0351 --- */
+ /*0351:*/ 15, 10, 6, 2, 5, /* width and bbox (w,h,x,y) */
+ /*0356:*/ 0xff,0xc0, /* ##########...... */
+ /*0358:*/ 0xff,0xc0, /* ##########...... */
+ /*035a:*/ 0x00,0x00, /* ................ */
+ /*035c:*/ 0x00,0x00, /* ................ */
+ /*035e:*/ 0xff,0xc0, /* ##########...... */
+ /*0360:*/ 0xff,0xc0, /* ##########...... */
+/* --- new character greater (62) starting at offset 0x0362 --- */
+ /*0362:*/ 15, 12, 12, 1, 1, /* width and bbox (w,h,x,y) */
+ /*0367:*/ 0xc0,0x00, /* ##.............. */
+ /*0369:*/ 0xf0,0x00, /* ####............ */
+ /*036b:*/ 0x3c,0x00, /* ..####.......... */
+ /*036d:*/ 0x0f,0x00, /* ....####........ */
+ /*036f:*/ 0x03,0xc0, /* ......####...... */
+ /*0371:*/ 0x00,0x70, /* .........###.... */
+ /*0373:*/ 0x00,0x70, /* .........###.... */
+ /*0375:*/ 0x03,0xc0, /* ......####...... */
+ /*0377:*/ 0x0f,0x00, /* ....####........ */
+ /*0379:*/ 0x3c,0x00, /* ..####.......... */
+ /*037b:*/ 0xf0,0x00, /* ####............ */
+ /*037d:*/ 0xc0,0x00, /* ##.............. */
+/* --- new character question (63) starting at offset 0x037f --- */
+ /*037f:*/ 12, 10, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0384:*/ 0x1f,0x00, /* ...#####........ */
+ /*0386:*/ 0x7f,0x80, /* .########....... */
+ /*0388:*/ 0x71,0xc0, /* .###...###...... */
+ /*038a:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*038c:*/ 0xc0,0xc0, /* ##......##...... */
+ /*038e:*/ 0xc1,0xc0, /* ##.....###...... */
+ /*0390:*/ 0x01,0x80, /* .......##....... */
+ /*0392:*/ 0x03,0x80, /* ......###....... */
+ /*0394:*/ 0x07,0x00, /* .....###........ */
+ /*0396:*/ 0x06,0x00, /* .....##......... */
+ /*0398:*/ 0x0c,0x00, /* ....##.......... */
+ /*039a:*/ 0x0c,0x00, /* ....##.......... */
+ /*039c:*/ 0x0c,0x00, /* ....##.......... */
+ /*039e:*/ 0x0c,0x00, /* ....##.......... */
+ /*03a0:*/ 0x00,0x00, /* ................ */
+ /*03a2:*/ 0x00,0x00, /* ................ */
+ /*03a4:*/ 0x0c,0x00, /* ....##.......... */
+ /*03a6:*/ 0x0c,0x00, /* ....##.......... */
+ /*03a8:*/ 0x0c,0x00, /* ....##.......... */
+/* --- new character at (64) starting at offset 0x03aa --- */
+ /*03aa:*/ 25, 22, 23, 2, -4, /* width and bbox (w,h,x,y) */
+ /*03af:*/ 0x00,0xff,0x00, /* ........########........ */
+ /*03b2:*/ 0x03,0xff,0xc0, /* ......############...... */
+ /*03b5:*/ 0x0f,0x01,0xe0, /* ....####.......####..... */
+ /*03b8:*/ 0x1c,0x00,0x70, /* ...###...........###.... */
+ /*03bb:*/ 0x38,0x00,0x18, /* ..###..............##... */
+ /*03be:*/ 0x30,0x00,0x18, /* ..##...............##... */
+ /*03c1:*/ 0x60,0x73,0x0c, /* .##......###..##....##.. */
+ /*03c4:*/ 0x60,0xfb,0x0c, /* .##.....#####.##....##.. */
+ /*03c7:*/ 0xc1,0xc7,0x0c, /* ##.....###...###....##.. */
+ /*03ca:*/ 0xc3,0x86,0x0c, /* ##....###....##.....##.. */
+ /*03cd:*/ 0xc3,0x06,0x0c, /* ##....##.....##.....##.. */
+ /*03d0:*/ 0xc6,0x06,0x0c, /* ##...##......##.....##.. */
+ /*03d3:*/ 0xc6,0x0c,0x1c, /* ##...##.....##.....###.. */
+ /*03d6:*/ 0xc6,0x0c,0x18, /* ##...##.....##.....##... */
+ /*03d9:*/ 0xc6,0x0c,0x38, /* ##...##.....##....###... */
+ /*03dc:*/ 0xe7,0x1c,0x70, /* ###..###...###...###.... */
+ /*03df:*/ 0x63,0xf7,0xe0, /* .##...######.######..... */
+ /*03e2:*/ 0x71,0xe3,0x80, /* .###...####...###....... */
+ /*03e5:*/ 0x38,0x00,0x00, /* ..###................... */
+ /*03e8:*/ 0x1c,0x00,0x00, /* ...###.................. */
+ /*03eb:*/ 0x0f,0x03,0x00, /* ....####......##........ */
+ /*03ee:*/ 0x07,0xff,0x00, /* .....###########........ */
+ /*03f1:*/ 0x00,0xfc,0x00, /* ........######.......... */
+/* --- new character A (65) starting at offset 0x03f4 --- */
+ /*03f4:*/ 17, 15, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*03f9:*/ 0x03,0x80, /* ......###....... */
+ /*03fb:*/ 0x03,0x80, /* ......###....... */
+ /*03fd:*/ 0x06,0xc0, /* .....##.##...... */
+ /*03ff:*/ 0x06,0xc0, /* .....##.##...... */
+ /*0401:*/ 0x0c,0x40, /* ....##...#...... */
+ /*0403:*/ 0x0c,0x60, /* ....##...##..... */
+ /*0405:*/ 0x0c,0x60, /* ....##...##..... */
+ /*0407:*/ 0x18,0x30, /* ...##.....##.... */
+ /*0409:*/ 0x18,0x30, /* ...##.....##.... */
+ /*040b:*/ 0x18,0x30, /* ...##.....##.... */
+ /*040d:*/ 0x30,0x18, /* ..##.......##... */
+ /*040f:*/ 0x3f,0xf8, /* ..###########... */
+ /*0411:*/ 0x3f,0xf8, /* ..###########... */
+ /*0413:*/ 0x60,0x0c, /* .##.........##.. */
+ /*0415:*/ 0x60,0x0c, /* .##.........##.. */
+ /*0417:*/ 0x60,0x0c, /* .##.........##.. */
+ /*0419:*/ 0xc0,0x06, /* ##...........##. */
+ /*041b:*/ 0xc0,0x06, /* ##...........##. */
+ /*041d:*/ 0xc0,0x06, /* ##...........##. */
+/* --- new character B (66) starting at offset 0x041f --- */
+ /*041f:*/ 17, 14, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0424:*/ 0xff,0xc0, /* ##########...... */
+ /*0426:*/ 0xff,0xf0, /* ############.... */
+ /*0428:*/ 0xc0,0x70, /* ##.......###.... */
+ /*042a:*/ 0xc0,0x18, /* ##.........##... */
+ /*042c:*/ 0xc0,0x18, /* ##.........##... */
+ /*042e:*/ 0xc0,0x18, /* ##.........##... */
+ /*0430:*/ 0xc0,0x18, /* ##.........##... */
+ /*0432:*/ 0xc0,0x30, /* ##........##.... */
+ /*0434:*/ 0xff,0xe0, /* ###########..... */
+ /*0436:*/ 0xff,0xf0, /* ############.... */
+ /*0438:*/ 0xc0,0x18, /* ##.........##... */
+ /*043a:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*043c:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*043e:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0440:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0442:*/ 0xc0,0x1c, /* ##.........###.. */
+ /*0444:*/ 0xc0,0x38, /* ##........###... */
+ /*0446:*/ 0xff,0xf0, /* ############.... */
+ /*0448:*/ 0xff,0xc0, /* ##########...... */
+/* --- new character C (67) starting at offset 0x044a --- */
+ /*044a:*/ 18, 16, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*044f:*/ 0x07,0xe0, /* .....######..... */
+ /*0451:*/ 0x1f,0xf8, /* ...##########... */
+ /*0453:*/ 0x3c,0x3c, /* ..####....####.. */
+ /*0455:*/ 0x70,0x0e, /* .###........###. */
+ /*0457:*/ 0x60,0x06, /* .##..........##. */
+ /*0459:*/ 0xe0,0x06, /* ###..........##. */
+ /*045b:*/ 0xc0,0x00, /* ##.............. */
+ /*045d:*/ 0xc0,0x00, /* ##.............. */
+ /*045f:*/ 0xc0,0x00, /* ##.............. */
+ /*0461:*/ 0xc0,0x00, /* ##.............. */
+ /*0463:*/ 0xc0,0x00, /* ##.............. */
+ /*0465:*/ 0xc0,0x00, /* ##.............. */
+ /*0467:*/ 0xc0,0x03, /* ##............## */
+ /*0469:*/ 0xe0,0x03, /* ###...........## */
+ /*046b:*/ 0x60,0x06, /* .##..........##. */
+ /*046d:*/ 0x70,0x0e, /* .###........###. */
+ /*046f:*/ 0x3c,0x3c, /* ..####....####.. */
+ /*0471:*/ 0x1f,0xf8, /* ...##########... */
+ /*0473:*/ 0x07,0xe0, /* .....######..... */
+/* --- new character D (68) starting at offset 0x0475 --- */
+ /*0475:*/ 18, 15, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*047a:*/ 0xff,0xc0, /* ##########...... */
+ /*047c:*/ 0xff,0xf0, /* ############.... */
+ /*047e:*/ 0xc0,0x78, /* ##.......####... */
+ /*0480:*/ 0xc0,0x1c, /* ##.........###.. */
+ /*0482:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0484:*/ 0xc0,0x0e, /* ##..........###. */
+ /*0486:*/ 0xc0,0x06, /* ##...........##. */
+ /*0488:*/ 0xc0,0x06, /* ##...........##. */
+ /*048a:*/ 0xc0,0x06, /* ##...........##. */
+ /*048c:*/ 0xc0,0x06, /* ##...........##. */
+ /*048e:*/ 0xc0,0x06, /* ##...........##. */
+ /*0490:*/ 0xc0,0x06, /* ##...........##. */
+ /*0492:*/ 0xc0,0x06, /* ##...........##. */
+ /*0494:*/ 0xc0,0x0e, /* ##..........###. */
+ /*0496:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0498:*/ 0xc0,0x1c, /* ##.........###.. */
+ /*049a:*/ 0xc0,0x78, /* ##.......####... */
+ /*049c:*/ 0xff,0xf0, /* ############.... */
+ /*049e:*/ 0xff,0xc0, /* ##########...... */
+/* --- new character E (69) starting at offset 0x04a0 --- */
+ /*04a0:*/ 16, 12, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*04a5:*/ 0xff,0xf0, /* ############.... */
+ /*04a7:*/ 0xff,0xf0, /* ############.... */
+ /*04a9:*/ 0xc0,0x00, /* ##.............. */
+ /*04ab:*/ 0xc0,0x00, /* ##.............. */
+ /*04ad:*/ 0xc0,0x00, /* ##.............. */
+ /*04af:*/ 0xc0,0x00, /* ##.............. */
+ /*04b1:*/ 0xc0,0x00, /* ##.............. */
+ /*04b3:*/ 0xc0,0x00, /* ##.............. */
+ /*04b5:*/ 0xff,0xe0, /* ###########..... */
+ /*04b7:*/ 0xff,0xe0, /* ###########..... */
+ /*04b9:*/ 0xc0,0x00, /* ##.............. */
+ /*04bb:*/ 0xc0,0x00, /* ##.............. */
+ /*04bd:*/ 0xc0,0x00, /* ##.............. */
+ /*04bf:*/ 0xc0,0x00, /* ##.............. */
+ /*04c1:*/ 0xc0,0x00, /* ##.............. */
+ /*04c3:*/ 0xc0,0x00, /* ##.............. */
+ /*04c5:*/ 0xc0,0x00, /* ##.............. */
+ /*04c7:*/ 0xff,0xf0, /* ############.... */
+ /*04c9:*/ 0xff,0xf0, /* ############.... */
+/* --- new character F (70) starting at offset 0x04cb --- */
+ /*04cb:*/ 14, 11, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*04d0:*/ 0xff,0xe0, /* ###########..... */
+ /*04d2:*/ 0xff,0xe0, /* ###########..... */
+ /*04d4:*/ 0xc0,0x00, /* ##.............. */
+ /*04d6:*/ 0xc0,0x00, /* ##.............. */
+ /*04d8:*/ 0xc0,0x00, /* ##.............. */
+ /*04da:*/ 0xc0,0x00, /* ##.............. */
+ /*04dc:*/ 0xc0,0x00, /* ##.............. */
+ /*04de:*/ 0xc0,0x00, /* ##.............. */
+ /*04e0:*/ 0xc0,0x00, /* ##.............. */
+ /*04e2:*/ 0xff,0xc0, /* ##########...... */
+ /*04e4:*/ 0xff,0xc0, /* ##########...... */
+ /*04e6:*/ 0xc0,0x00, /* ##.............. */
+ /*04e8:*/ 0xc0,0x00, /* ##.............. */
+ /*04ea:*/ 0xc0,0x00, /* ##.............. */
+ /*04ec:*/ 0xc0,0x00, /* ##.............. */
+ /*04ee:*/ 0xc0,0x00, /* ##.............. */
+ /*04f0:*/ 0xc0,0x00, /* ##.............. */
+ /*04f2:*/ 0xc0,0x00, /* ##.............. */
+ /*04f4:*/ 0xc0,0x00, /* ##.............. */
+/* --- new character G (71) starting at offset 0x04f6 --- */
+ /*04f6:*/ 19, 16, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*04fb:*/ 0x07,0xe0, /* .....######..... */
+ /*04fd:*/ 0x1f,0xf8, /* ...##########... */
+ /*04ff:*/ 0x3c,0x3c, /* ..####....####.. */
+ /*0501:*/ 0x70,0x0e, /* .###........###. */
+ /*0503:*/ 0x60,0x06, /* .##..........##. */
+ /*0505:*/ 0xe0,0x06, /* ###..........##. */
+ /*0507:*/ 0xc0,0x00, /* ##.............. */
+ /*0509:*/ 0xc0,0x00, /* ##.............. */
+ /*050b:*/ 0xc0,0x00, /* ##.............. */
+ /*050d:*/ 0xc0,0x7f, /* ##.......####### */
+ /*050f:*/ 0xc0,0x7f, /* ##.......####### */
+ /*0511:*/ 0xc0,0x03, /* ##............## */
+ /*0513:*/ 0xc0,0x03, /* ##............## */
+ /*0515:*/ 0xe0,0x03, /* ###...........## */
+ /*0517:*/ 0x60,0x07, /* .##..........### */
+ /*0519:*/ 0x70,0x0f, /* .###........#### */
+ /*051b:*/ 0x3c,0x3f, /* ..####....###### */
+ /*051d:*/ 0x1f,0xfb, /* ...##########.## */
+ /*051f:*/ 0x07,0xe3, /* .....######...## */
+/* --- new character H (72) starting at offset 0x0521 --- */
+ /*0521:*/ 18, 14, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0526:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0528:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*052a:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*052c:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*052e:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0530:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0532:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0534:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0536:*/ 0xff,0xfc, /* ##############.. */
+ /*0538:*/ 0xff,0xfc, /* ##############.. */
+ /*053a:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*053c:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*053e:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0540:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0542:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0544:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0546:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0548:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*054a:*/ 0xc0,0x0c, /* ##..........##.. */
+/* --- new character I (73) starting at offset 0x054c --- */
+ /*054c:*/ 8, 2, 19, 3, 0, /* width and bbox (w,h,x,y) */
+ /*0551:*/ 0xc0, /* ##...... */
+ /*0552:*/ 0xc0, /* ##...... */
+ /*0553:*/ 0xc0, /* ##...... */
+ /*0554:*/ 0xc0, /* ##...... */
+ /*0555:*/ 0xc0, /* ##...... */
+ /*0556:*/ 0xc0, /* ##...... */
+ /*0557:*/ 0xc0, /* ##...... */
+ /*0558:*/ 0xc0, /* ##...... */
+ /*0559:*/ 0xc0, /* ##...... */
+ /*055a:*/ 0xc0, /* ##...... */
+ /*055b:*/ 0xc0, /* ##...... */
+ /*055c:*/ 0xc0, /* ##...... */
+ /*055d:*/ 0xc0, /* ##...... */
+ /*055e:*/ 0xc0, /* ##...... */
+ /*055f:*/ 0xc0, /* ##...... */
+ /*0560:*/ 0xc0, /* ##...... */
+ /*0561:*/ 0xc0, /* ##...... */
+ /*0562:*/ 0xc0, /* ##...... */
+ /*0563:*/ 0xc0, /* ##...... */
+/* --- new character J (74) starting at offset 0x0564 --- */
+ /*0564:*/ 13, 10, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0569:*/ 0x00,0xc0, /* ........##...... */
+ /*056b:*/ 0x00,0xc0, /* ........##...... */
+ /*056d:*/ 0x00,0xc0, /* ........##...... */
+ /*056f:*/ 0x00,0xc0, /* ........##...... */
+ /*0571:*/ 0x00,0xc0, /* ........##...... */
+ /*0573:*/ 0x00,0xc0, /* ........##...... */
+ /*0575:*/ 0x00,0xc0, /* ........##...... */
+ /*0577:*/ 0x00,0xc0, /* ........##...... */
+ /*0579:*/ 0x00,0xc0, /* ........##...... */
+ /*057b:*/ 0x00,0xc0, /* ........##...... */
+ /*057d:*/ 0x00,0xc0, /* ........##...... */
+ /*057f:*/ 0x00,0xc0, /* ........##...... */
+ /*0581:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0583:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0585:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0587:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0589:*/ 0x61,0x80, /* .##....##....... */
+ /*058b:*/ 0x7f,0x80, /* .########....... */
+ /*058d:*/ 0x3f,0x00, /* ..######........ */
+/* --- new character K (75) starting at offset 0x058f --- */
+ /*058f:*/ 18, 15, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0594:*/ 0xc0,0x38, /* ##........###... */
+ /*0596:*/ 0xc0,0x70, /* ##.......###.... */
+ /*0598:*/ 0xc0,0xe0, /* ##......###..... */
+ /*059a:*/ 0xc1,0xc0, /* ##.....###...... */
+ /*059c:*/ 0xc3,0x80, /* ##....###....... */
+ /*059e:*/ 0xc7,0x00, /* ##...###........ */
+ /*05a0:*/ 0xce,0x00, /* ##..###......... */
+ /*05a2:*/ 0xdc,0x00, /* ##.###.......... */
+ /*05a4:*/ 0xfc,0x00, /* ######.......... */
+ /*05a6:*/ 0xfe,0x00, /* #######......... */
+ /*05a8:*/ 0xe7,0x00, /* ###..###........ */
+ /*05aa:*/ 0xc3,0x80, /* ##....###....... */
+ /*05ac:*/ 0xc1,0xc0, /* ##.....###...... */
+ /*05ae:*/ 0xc0,0xe0, /* ##......###..... */
+ /*05b0:*/ 0xc0,0x70, /* ##.......###.... */
+ /*05b2:*/ 0xc0,0x38, /* ##........###... */
+ /*05b4:*/ 0xc0,0x1c, /* ##.........###.. */
+ /*05b6:*/ 0xc0,0x0e, /* ##..........###. */
+ /*05b8:*/ 0xc0,0x06, /* ##...........##. */
+/* --- new character L (76) starting at offset 0x05ba --- */
+ /*05ba:*/ 14, 11, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*05bf:*/ 0xc0,0x00, /* ##.............. */
+ /*05c1:*/ 0xc0,0x00, /* ##.............. */
+ /*05c3:*/ 0xc0,0x00, /* ##.............. */
+ /*05c5:*/ 0xc0,0x00, /* ##.............. */
+ /*05c7:*/ 0xc0,0x00, /* ##.............. */
+ /*05c9:*/ 0xc0,0x00, /* ##.............. */
+ /*05cb:*/ 0xc0,0x00, /* ##.............. */
+ /*05cd:*/ 0xc0,0x00, /* ##.............. */
+ /*05cf:*/ 0xc0,0x00, /* ##.............. */
+ /*05d1:*/ 0xc0,0x00, /* ##.............. */
+ /*05d3:*/ 0xc0,0x00, /* ##.............. */
+ /*05d5:*/ 0xc0,0x00, /* ##.............. */
+ /*05d7:*/ 0xc0,0x00, /* ##.............. */
+ /*05d9:*/ 0xc0,0x00, /* ##.............. */
+ /*05db:*/ 0xc0,0x00, /* ##.............. */
+ /*05dd:*/ 0xc0,0x00, /* ##.............. */
+ /*05df:*/ 0xc0,0x00, /* ##.............. */
+ /*05e1:*/ 0xff,0xe0, /* ###########..... */
+ /*05e3:*/ 0xff,0xe0, /* ###########..... */
+/* --- new character M (77) starting at offset 0x05e5 --- */
+ /*05e5:*/ 21, 17, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*05ea:*/ 0xc0,0x01,0x80, /* ##.............##....... */
+ /*05ed:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*05f0:*/ 0xe0,0x03,0x80, /* ###...........###....... */
+ /*05f3:*/ 0xf0,0x07,0x80, /* ####.........####....... */
+ /*05f6:*/ 0xf0,0x07,0x80, /* ####.........####....... */
+ /*05f9:*/ 0xd8,0x0d,0x80, /* ##.##.......##.##....... */
+ /*05fc:*/ 0xd8,0x0d,0x80, /* ##.##.......##.##....... */
+ /*05ff:*/ 0xd8,0x0d,0x80, /* ##.##.......##.##....... */
+ /*0602:*/ 0xcc,0x19,0x80, /* ##..##.....##..##....... */
+ /*0605:*/ 0xcc,0x19,0x80, /* ##..##.....##..##....... */
+ /*0608:*/ 0xcc,0x19,0x80, /* ##..##.....##..##....... */
+ /*060b:*/ 0xc6,0x31,0x80, /* ##...##...##...##....... */
+ /*060e:*/ 0xc6,0x31,0x80, /* ##...##...##...##....... */
+ /*0611:*/ 0xc6,0x31,0x80, /* ##...##...##...##....... */
+ /*0614:*/ 0xc3,0x61,0x80, /* ##....##.##....##....... */
+ /*0617:*/ 0xc3,0x61,0x80, /* ##....##.##....##....... */
+ /*061a:*/ 0xc3,0x61,0x80, /* ##....##.##....##....... */
+ /*061d:*/ 0xc1,0xc1,0x80, /* ##.....###.....##....... */
+ /*0620:*/ 0xc1,0xc1,0x80, /* ##.....###.....##....... */
+/* --- new character N (78) starting at offset 0x0623 --- */
+ /*0623:*/ 18, 14, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0628:*/ 0xe0,0x0c, /* ###.........##.. */
+ /*062a:*/ 0xf0,0x0c, /* ####........##.. */
+ /*062c:*/ 0xf0,0x0c, /* ####........##.. */
+ /*062e:*/ 0xd8,0x0c, /* ##.##.......##.. */
+ /*0630:*/ 0xdc,0x0c, /* ##.###......##.. */
+ /*0632:*/ 0xcc,0x0c, /* ##..##......##.. */
+ /*0634:*/ 0xce,0x0c, /* ##..###.....##.. */
+ /*0636:*/ 0xc6,0x0c, /* ##...##.....##.. */
+ /*0638:*/ 0xc7,0x0c, /* ##...###....##.. */
+ /*063a:*/ 0xc3,0x0c, /* ##....##....##.. */
+ /*063c:*/ 0xc3,0x8c, /* ##....###...##.. */
+ /*063e:*/ 0xc1,0x8c, /* ##.....##...##.. */
+ /*0640:*/ 0xc1,0xcc, /* ##.....###..##.. */
+ /*0642:*/ 0xc0,0xcc, /* ##......##..##.. */
+ /*0644:*/ 0xc0,0xec, /* ##......###.##.. */
+ /*0646:*/ 0xc0,0x6c, /* ##.......##.##.. */
+ /*0648:*/ 0xc0,0x3c, /* ##........####.. */
+ /*064a:*/ 0xc0,0x3c, /* ##........####.. */
+ /*064c:*/ 0xc0,0x1c, /* ##.........###.. */
+/* --- new character O (79) starting at offset 0x064e --- */
+ /*064e:*/ 18, 16, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0653:*/ 0x07,0xe0, /* .....######..... */
+ /*0655:*/ 0x1f,0xf8, /* ...##########... */
+ /*0657:*/ 0x3c,0x3c, /* ..####....####.. */
+ /*0659:*/ 0x70,0x0e, /* .###........###. */
+ /*065b:*/ 0x60,0x06, /* .##..........##. */
+ /*065d:*/ 0xe0,0x07, /* ###..........### */
+ /*065f:*/ 0xc0,0x03, /* ##............## */
+ /*0661:*/ 0xc0,0x03, /* ##............## */
+ /*0663:*/ 0xc0,0x03, /* ##............## */
+ /*0665:*/ 0xc0,0x03, /* ##............## */
+ /*0667:*/ 0xc0,0x03, /* ##............## */
+ /*0669:*/ 0xc0,0x03, /* ##............## */
+ /*066b:*/ 0xc0,0x03, /* ##............## */
+ /*066d:*/ 0xe0,0x07, /* ###..........### */
+ /*066f:*/ 0x60,0x06, /* .##..........##. */
+ /*0671:*/ 0x70,0x0e, /* .###........###. */
+ /*0673:*/ 0x3c,0x3c, /* ..####....####.. */
+ /*0675:*/ 0x1f,0xf8, /* ...##########... */
+ /*0677:*/ 0x07,0xe0, /* .....######..... */
+/* --- new character P (80) starting at offset 0x0679 --- */
+ /*0679:*/ 16, 13, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*067e:*/ 0xff,0xe0, /* ###########..... */
+ /*0680:*/ 0xff,0xf0, /* ############.... */
+ /*0682:*/ 0xc0,0x30, /* ##........##.... */
+ /*0684:*/ 0xc0,0x18, /* ##.........##... */
+ /*0686:*/ 0xc0,0x18, /* ##.........##... */
+ /*0688:*/ 0xc0,0x18, /* ##.........##... */
+ /*068a:*/ 0xc0,0x18, /* ##.........##... */
+ /*068c:*/ 0xc0,0x30, /* ##........##.... */
+ /*068e:*/ 0xff,0xf0, /* ############.... */
+ /*0690:*/ 0xff,0xe0, /* ###########..... */
+ /*0692:*/ 0xc0,0x00, /* ##.............. */
+ /*0694:*/ 0xc0,0x00, /* ##.............. */
+ /*0696:*/ 0xc0,0x00, /* ##.............. */
+ /*0698:*/ 0xc0,0x00, /* ##.............. */
+ /*069a:*/ 0xc0,0x00, /* ##.............. */
+ /*069c:*/ 0xc0,0x00, /* ##.............. */
+ /*069e:*/ 0xc0,0x00, /* ##.............. */
+ /*06a0:*/ 0xc0,0x00, /* ##.............. */
+ /*06a2:*/ 0xc0,0x00, /* ##.............. */
+/* --- new character Q (81) starting at offset 0x06a4 --- */
+ /*06a4:*/ 18, 16, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*06a9:*/ 0x07,0xe0, /* .....######..... */
+ /*06ab:*/ 0x1f,0xf8, /* ...##########... */
+ /*06ad:*/ 0x3c,0x3c, /* ..####....####.. */
+ /*06af:*/ 0x70,0x0e, /* .###........###. */
+ /*06b1:*/ 0x60,0x06, /* .##..........##. */
+ /*06b3:*/ 0xe0,0x07, /* ###..........### */
+ /*06b5:*/ 0xc0,0x03, /* ##............## */
+ /*06b7:*/ 0xc0,0x03, /* ##............## */
+ /*06b9:*/ 0xc0,0x03, /* ##............## */
+ /*06bb:*/ 0xc0,0x03, /* ##............## */
+ /*06bd:*/ 0xc0,0x03, /* ##............## */
+ /*06bf:*/ 0xc0,0x03, /* ##............## */
+ /*06c1:*/ 0xc0,0x03, /* ##............## */
+ /*06c3:*/ 0xe0,0x07, /* ###..........### */
+ /*06c5:*/ 0x60,0xe6, /* .##.....###..##. */
+ /*06c7:*/ 0x70,0x7e, /* .###.....######. */
+ /*06c9:*/ 0x3c,0x1c, /* ..####.....###.. */
+ /*06cb:*/ 0x1f,0xfe, /* ...############. */
+ /*06cd:*/ 0x07,0xe7, /* .....######..### */
+/* --- new character R (82) starting at offset 0x06cf --- */
+ /*06cf:*/ 17, 13, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*06d4:*/ 0xff,0xe0, /* ###########..... */
+ /*06d6:*/ 0xff,0xf0, /* ############.... */
+ /*06d8:*/ 0xc0,0x30, /* ##........##.... */
+ /*06da:*/ 0xc0,0x18, /* ##.........##... */
+ /*06dc:*/ 0xc0,0x18, /* ##.........##... */
+ /*06de:*/ 0xc0,0x18, /* ##.........##... */
+ /*06e0:*/ 0xc0,0x18, /* ##.........##... */
+ /*06e2:*/ 0xc0,0x30, /* ##........##.... */
+ /*06e4:*/ 0xff,0xf0, /* ############.... */
+ /*06e6:*/ 0xff,0xe0, /* ###########..... */
+ /*06e8:*/ 0xc0,0x70, /* ##.......###.... */
+ /*06ea:*/ 0xc0,0x30, /* ##........##.... */
+ /*06ec:*/ 0xc0,0x18, /* ##.........##... */
+ /*06ee:*/ 0xc0,0x18, /* ##.........##... */
+ /*06f0:*/ 0xc0,0x18, /* ##.........##... */
+ /*06f2:*/ 0xc0,0x18, /* ##.........##... */
+ /*06f4:*/ 0xc0,0x18, /* ##.........##... */
+ /*06f6:*/ 0xc0,0x18, /* ##.........##... */
+ /*06f8:*/ 0xc0,0x18, /* ##.........##... */
+/* --- new character S (83) starting at offset 0x06fa --- */
+ /*06fa:*/ 16, 14, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*06ff:*/ 0x07,0xc0, /* .....#####...... */
+ /*0701:*/ 0x1f,0xf0, /* ...#########.... */
+ /*0703:*/ 0x38,0x38, /* ..###.....###... */
+ /*0705:*/ 0x70,0x18, /* .###.......##... */
+ /*0707:*/ 0x60,0x18, /* .##........##... */
+ /*0709:*/ 0x60,0x00, /* .##............. */
+ /*070b:*/ 0x70,0x00, /* .###............ */
+ /*070d:*/ 0x3e,0x00, /* ..#####......... */
+ /*070f:*/ 0x0f,0xc0, /* ....######...... */
+ /*0711:*/ 0x01,0xf0, /* .......#####.... */
+ /*0713:*/ 0x00,0x78, /* .........####... */
+ /*0715:*/ 0x00,0x1c, /* ...........###.. */
+ /*0717:*/ 0x00,0x0c, /* ............##.. */
+ /*0719:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*071b:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*071d:*/ 0xe0,0x1c, /* ###........###.. */
+ /*071f:*/ 0x78,0x38, /* .####.....###... */
+ /*0721:*/ 0x3f,0xf0, /* ..##########.... */
+ /*0723:*/ 0x0f,0xc0, /* ....######...... */
+/* --- new character T (84) starting at offset 0x0725 --- */
+ /*0725:*/ 16, 14, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*072a:*/ 0xff,0xfc, /* ##############.. */
+ /*072c:*/ 0xff,0xfc, /* ##############.. */
+ /*072e:*/ 0x03,0x00, /* ......##........ */
+ /*0730:*/ 0x03,0x00, /* ......##........ */
+ /*0732:*/ 0x03,0x00, /* ......##........ */
+ /*0734:*/ 0x03,0x00, /* ......##........ */
+ /*0736:*/ 0x03,0x00, /* ......##........ */
+ /*0738:*/ 0x03,0x00, /* ......##........ */
+ /*073a:*/ 0x03,0x00, /* ......##........ */
+ /*073c:*/ 0x03,0x00, /* ......##........ */
+ /*073e:*/ 0x03,0x00, /* ......##........ */
+ /*0740:*/ 0x03,0x00, /* ......##........ */
+ /*0742:*/ 0x03,0x00, /* ......##........ */
+ /*0744:*/ 0x03,0x00, /* ......##........ */
+ /*0746:*/ 0x03,0x00, /* ......##........ */
+ /*0748:*/ 0x03,0x00, /* ......##........ */
+ /*074a:*/ 0x03,0x00, /* ......##........ */
+ /*074c:*/ 0x03,0x00, /* ......##........ */
+ /*074e:*/ 0x03,0x00, /* ......##........ */
+/* --- new character U (85) starting at offset 0x0750 --- */
+ /*0750:*/ 18, 14, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0755:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0757:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0759:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*075b:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*075d:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*075f:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0761:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0763:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0765:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0767:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0769:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*076b:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*076d:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*076f:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0771:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0773:*/ 0x60,0x18, /* .##........##... */
+ /*0775:*/ 0x70,0x38, /* .###......###... */
+ /*0777:*/ 0x3f,0xf0, /* ..##########.... */
+ /*0779:*/ 0x0f,0xc0, /* ....######...... */
+/* --- new character V (86) starting at offset 0x077b --- */
+ /*077b:*/ 17, 15, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0780:*/ 0xc0,0x06, /* ##...........##. */
+ /*0782:*/ 0xc0,0x06, /* ##...........##. */
+ /*0784:*/ 0xe0,0x0e, /* ###.........###. */
+ /*0786:*/ 0x60,0x0c, /* .##.........##.. */
+ /*0788:*/ 0x70,0x1c, /* .###.......###.. */
+ /*078a:*/ 0x30,0x18, /* ..##.......##... */
+ /*078c:*/ 0x30,0x18, /* ..##.......##... */
+ /*078e:*/ 0x38,0x38, /* ..###.....###... */
+ /*0790:*/ 0x18,0x30, /* ...##.....##.... */
+ /*0792:*/ 0x18,0x30, /* ...##.....##.... */
+ /*0794:*/ 0x1c,0x70, /* ...###...###.... */
+ /*0796:*/ 0x0c,0x60, /* ....##...##..... */
+ /*0798:*/ 0x0c,0x60, /* ....##...##..... */
+ /*079a:*/ 0x0e,0xe0, /* ....###.###..... */
+ /*079c:*/ 0x06,0xc0, /* .....##.##...... */
+ /*079e:*/ 0x06,0xc0, /* .....##.##...... */
+ /*07a0:*/ 0x03,0x80, /* ......###....... */
+ /*07a2:*/ 0x03,0x80, /* ......###....... */
+ /*07a4:*/ 0x03,0x80, /* ......###....... */
+/* --- new character W (87) starting at offset 0x07a6 --- */
+ /*07a6:*/ 22, 20, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*07ab:*/ 0xc0,0x60,0x30, /* ##.......##.......##.... */
+ /*07ae:*/ 0xc0,0x60,0x30, /* ##.......##.......##.... */
+ /*07b1:*/ 0xc0,0x60,0x30, /* ##.......##.......##.... */
+ /*07b4:*/ 0xc0,0xf0,0x30, /* ##......####......##.... */
+ /*07b7:*/ 0x60,0xf0,0x60, /* .##.....####.....##..... */
+ /*07ba:*/ 0x61,0x98,0x60, /* .##....##..##....##..... */
+ /*07bd:*/ 0x61,0x98,0x60, /* .##....##..##....##..... */
+ /*07c0:*/ 0x61,0x98,0x60, /* .##....##..##....##..... */
+ /*07c3:*/ 0x61,0x98,0x60, /* .##....##..##....##..... */
+ /*07c6:*/ 0x31,0x98,0xc0, /* ..##...##..##...##...... */
+ /*07c9:*/ 0x33,0x0c,0xc0, /* ..##..##....##..##...... */
+ /*07cc:*/ 0x33,0x0c,0xc0, /* ..##..##....##..##...... */
+ /*07cf:*/ 0x33,0x0c,0xc0, /* ..##..##....##..##...... */
+ /*07d2:*/ 0x1b,0x0d,0x80, /* ...##.##....##.##....... */
+ /*07d5:*/ 0x1b,0x0d,0x80, /* ...##.##....##.##....... */
+ /*07d8:*/ 0x1e,0x07,0x80, /* ...####......####....... */
+ /*07db:*/ 0x0e,0x07,0x00, /* ....###......###........ */
+ /*07de:*/ 0x0c,0x03,0x00, /* ....##........##........ */
+ /*07e1:*/ 0x0c,0x03,0x00, /* ....##........##........ */
+/* --- new character X (88) starting at offset 0x07e4 --- */
+ /*07e4:*/ 17, 15, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*07e9:*/ 0xc0,0x06, /* ##...........##. */
+ /*07eb:*/ 0xe0,0x0e, /* ###.........###. */
+ /*07ed:*/ 0x70,0x1c, /* .###.......###.. */
+ /*07ef:*/ 0x30,0x18, /* ..##.......##... */
+ /*07f1:*/ 0x18,0x30, /* ...##.....##.... */
+ /*07f3:*/ 0x1c,0x70, /* ...###...###.... */
+ /*07f5:*/ 0x0e,0xe0, /* ....###.###..... */
+ /*07f7:*/ 0x07,0xc0, /* .....#####...... */
+ /*07f9:*/ 0x03,0x80, /* ......###....... */
+ /*07fb:*/ 0x03,0x80, /* ......###....... */
+ /*07fd:*/ 0x07,0xc0, /* .....#####...... */
+ /*07ff:*/ 0x0e,0xe0, /* ....###.###..... */
+ /*0801:*/ 0x0c,0x60, /* ....##...##..... */
+ /*0803:*/ 0x1c,0x70, /* ...###...###.... */
+ /*0805:*/ 0x38,0x38, /* ..###.....###... */
+ /*0807:*/ 0x30,0x18, /* ..##.......##... */
+ /*0809:*/ 0x60,0x0c, /* .##.........##.. */
+ /*080b:*/ 0xe0,0x0e, /* ###.........###. */
+ /*080d:*/ 0xc0,0x06, /* ##...........##. */
+/* --- new character Y (89) starting at offset 0x080f --- */
+ /*080f:*/ 16, 14, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0814:*/ 0xc0,0x0c, /* ##..........##.. */
+ /*0816:*/ 0xe0,0x1c, /* ###........###.. */
+ /*0818:*/ 0x60,0x18, /* .##........##... */
+ /*081a:*/ 0x70,0x38, /* .###......###... */
+ /*081c:*/ 0x30,0x30, /* ..##......##.... */
+ /*081e:*/ 0x38,0x70, /* ..###....###.... */
+ /*0820:*/ 0x18,0x60, /* ...##....##..... */
+ /*0822:*/ 0x1c,0xe0, /* ...###..###..... */
+ /*0824:*/ 0x0c,0xc0, /* ....##..##...... */
+ /*0826:*/ 0x0f,0xc0, /* ....######...... */
+ /*0828:*/ 0x07,0x80, /* .....####....... */
+ /*082a:*/ 0x07,0x80, /* .....####....... */
+ /*082c:*/ 0x03,0x00, /* ......##........ */
+ /*082e:*/ 0x03,0x00, /* ......##........ */
+ /*0830:*/ 0x03,0x00, /* ......##........ */
+ /*0832:*/ 0x03,0x00, /* ......##........ */
+ /*0834:*/ 0x03,0x00, /* ......##........ */
+ /*0836:*/ 0x03,0x00, /* ......##........ */
+ /*0838:*/ 0x03,0x00, /* ......##........ */
+/* --- new character Z (90) starting at offset 0x083a --- */
+ /*083a:*/ 15, 13, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*083f:*/ 0xff,0xf8, /* #############... */
+ /*0841:*/ 0xff,0xf8, /* #############... */
+ /*0843:*/ 0x00,0x38, /* ..........###... */
+ /*0845:*/ 0x00,0x70, /* .........###.... */
+ /*0847:*/ 0x00,0xe0, /* ........###..... */
+ /*0849:*/ 0x01,0xc0, /* .......###...... */
+ /*084b:*/ 0x01,0xc0, /* .......###...... */
+ /*084d:*/ 0x03,0x80, /* ......###....... */
+ /*084f:*/ 0x07,0x00, /* .....###........ */
+ /*0851:*/ 0x07,0x00, /* .....###........ */
+ /*0853:*/ 0x0e,0x00, /* ....###......... */
+ /*0855:*/ 0x1c,0x00, /* ...###.......... */
+ /*0857:*/ 0x1c,0x00, /* ...###.......... */
+ /*0859:*/ 0x38,0x00, /* ..###........... */
+ /*085b:*/ 0x70,0x00, /* .###............ */
+ /*085d:*/ 0x70,0x00, /* .###............ */
+ /*085f:*/ 0xe0,0x00, /* ###............. */
+ /*0861:*/ 0xff,0xf8, /* #############... */
+ /*0863:*/ 0xff,0xf8, /* #############... */
+/* --- new character bracketleft (91) starting at offset 0x0865 --- */
+ /*0865:*/ 7, 4, 24, 2, -5, /* width and bbox (w,h,x,y) */
+ /*086a:*/ 0xf0, /* ####.... */
+ /*086b:*/ 0xf0, /* ####.... */
+ /*086c:*/ 0xc0, /* ##...... */
+ /*086d:*/ 0xc0, /* ##...... */
+ /*086e:*/ 0xc0, /* ##...... */
+ /*086f:*/ 0xc0, /* ##...... */
+ /*0870:*/ 0xc0, /* ##...... */
+ /*0871:*/ 0xc0, /* ##...... */
+ /*0872:*/ 0xc0, /* ##...... */
+ /*0873:*/ 0xc0, /* ##...... */
+ /*0874:*/ 0xc0, /* ##...... */
+ /*0875:*/ 0xc0, /* ##...... */
+ /*0876:*/ 0xc0, /* ##...... */
+ /*0877:*/ 0xc0, /* ##...... */
+ /*0878:*/ 0xc0, /* ##...... */
+ /*0879:*/ 0xc0, /* ##...... */
+ /*087a:*/ 0xc0, /* ##...... */
+ /*087b:*/ 0xc0, /* ##...... */
+ /*087c:*/ 0xc0, /* ##...... */
+ /*087d:*/ 0xc0, /* ##...... */
+ /*087e:*/ 0xc0, /* ##...... */
+ /*087f:*/ 0xc0, /* ##...... */
+ /*0880:*/ 0xf0, /* ####.... */
+ /*0881:*/ 0xf0, /* ####.... */
+/* --- new character backslash (92) starting at offset 0x0882 --- */
+ /*0882:*/ 7, 7, 19, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0887:*/ 0xc0, /* ##...... */
+ /*0888:*/ 0xc0, /* ##...... */
+ /*0889:*/ 0xc0, /* ##...... */
+ /*088a:*/ 0x60, /* .##..... */
+ /*088b:*/ 0x60, /* .##..... */
+ /*088c:*/ 0x60, /* .##..... */
+ /*088d:*/ 0x30, /* ..##.... */
+ /*088e:*/ 0x30, /* ..##.... */
+ /*088f:*/ 0x30, /* ..##.... */
+ /*0890:*/ 0x30, /* ..##.... */
+ /*0891:*/ 0x18, /* ...##... */
+ /*0892:*/ 0x18, /* ...##... */
+ /*0893:*/ 0x18, /* ...##... */
+ /*0894:*/ 0x0c, /* ....##.. */
+ /*0895:*/ 0x0c, /* ....##.. */
+ /*0896:*/ 0x0c, /* ....##.. */
+ /*0897:*/ 0x06, /* .....##. */
+ /*0898:*/ 0x06, /* .....##. */
+ /*0899:*/ 0x06, /* .....##. */
+/* --- new character bracketright (93) starting at offset 0x089a --- */
+ /*089a:*/ 7, 4, 24, 1, -5, /* width and bbox (w,h,x,y) */
+ /*089f:*/ 0xf0, /* ####.... */
+ /*08a0:*/ 0xf0, /* ####.... */
+ /*08a1:*/ 0x30, /* ..##.... */
+ /*08a2:*/ 0x30, /* ..##.... */
+ /*08a3:*/ 0x30, /* ..##.... */
+ /*08a4:*/ 0x30, /* ..##.... */
+ /*08a5:*/ 0x30, /* ..##.... */
+ /*08a6:*/ 0x30, /* ..##.... */
+ /*08a7:*/ 0x30, /* ..##.... */
+ /*08a8:*/ 0x30, /* ..##.... */
+ /*08a9:*/ 0x30, /* ..##.... */
+ /*08aa:*/ 0x30, /* ..##.... */
+ /*08ab:*/ 0x30, /* ..##.... */
+ /*08ac:*/ 0x30, /* ..##.... */
+ /*08ad:*/ 0x30, /* ..##.... */
+ /*08ae:*/ 0x30, /* ..##.... */
+ /*08af:*/ 0x30, /* ..##.... */
+ /*08b0:*/ 0x30, /* ..##.... */
+ /*08b1:*/ 0x30, /* ..##.... */
+ /*08b2:*/ 0x30, /* ..##.... */
+ /*08b3:*/ 0x30, /* ..##.... */
+ /*08b4:*/ 0x30, /* ..##.... */
+ /*08b5:*/ 0xf0, /* ####.... */
+ /*08b6:*/ 0xf0, /* ####.... */
+/* --- new character asciicircum (94) starting at offset 0x08b7 --- */
+ /*08b7:*/ 12, 10, 9, 1, 10, /* width and bbox (w,h,x,y) */
+ /*08bc:*/ 0x0c,0x00, /* ....##.......... */
+ /*08be:*/ 0x0c,0x00, /* ....##.......... */
+ /*08c0:*/ 0x1e,0x00, /* ...####......... */
+ /*08c2:*/ 0x12,0x00, /* ...#..#......... */
+ /*08c4:*/ 0x33,0x00, /* ..##..##........ */
+ /*08c6:*/ 0x61,0x80, /* .##....##....... */
+ /*08c8:*/ 0x61,0x80, /* .##....##....... */
+ /*08ca:*/ 0xc0,0xc0, /* ##......##...... */
+ /*08cc:*/ 0xc0,0xc0, /* ##......##...... */
+/* --- new character underscore (95) starting at offset 0x08ce --- */
+ /*08ce:*/ 14, 14, 2, 0, -5, /* width and bbox (w,h,x,y) */
+ /*08d3:*/ 0xff,0xfc, /* ##############.. */
+ /*08d5:*/ 0xff,0xfc, /* ##############.. */
+/* --- new character grave (96) starting at offset 0x08d7 --- */
+ /*08d7:*/ 7, 5, 4, 1, 15, /* width and bbox (w,h,x,y) */
+ /*08dc:*/ 0xc0, /* ##...... */
+ /*08dd:*/ 0x60, /* .##..... */
+ /*08de:*/ 0x30, /* ..##.... */
+ /*08df:*/ 0x18, /* ...##... */
+/* --- new character a (97) starting at offset 0x08e0 --- */
+ /*08e0:*/ 13, 11, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*08e5:*/ 0x1f,0x00, /* ...#####........ */
+ /*08e7:*/ 0x3f,0x80, /* ..#######....... */
+ /*08e9:*/ 0x61,0xc0, /* .##....###...... */
+ /*08eb:*/ 0x60,0xc0, /* .##.....##...... */
+ /*08ed:*/ 0x00,0xc0, /* ........##...... */
+ /*08ef:*/ 0x07,0xc0, /* .....#####...... */
+ /*08f1:*/ 0x3f,0xc0, /* ..########...... */
+ /*08f3:*/ 0x78,0xc0, /* .####...##...... */
+ /*08f5:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*08f7:*/ 0xc0,0xc0, /* ##......##...... */
+ /*08f9:*/ 0xc1,0xc0, /* ##.....###...... */
+ /*08fb:*/ 0xe3,0xc0, /* ###...####...... */
+ /*08fd:*/ 0x7e,0xe0, /* .######.###..... */
+ /*08ff:*/ 0x3c,0x60, /* ..####...##..... */
+/* --- new character b (98) starting at offset 0x0901 --- */
+ /*0901:*/ 14, 11, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0906:*/ 0xc0,0x00, /* ##.............. */
+ /*0908:*/ 0xc0,0x00, /* ##.............. */
+ /*090a:*/ 0xc0,0x00, /* ##.............. */
+ /*090c:*/ 0xc0,0x00, /* ##.............. */
+ /*090e:*/ 0xc0,0x00, /* ##.............. */
+ /*0910:*/ 0xcf,0x00, /* ##..####........ */
+ /*0912:*/ 0xdf,0x80, /* ##.######....... */
+ /*0914:*/ 0xf1,0xc0, /* ####...###...... */
+ /*0916:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*0918:*/ 0xc0,0x60, /* ##.......##..... */
+ /*091a:*/ 0xc0,0x60, /* ##.......##..... */
+ /*091c:*/ 0xc0,0x60, /* ##.......##..... */
+ /*091e:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0920:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0922:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0924:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*0926:*/ 0xf1,0xc0, /* ####...###...... */
+ /*0928:*/ 0xdf,0x80, /* ##.######....... */
+ /*092a:*/ 0xcf,0x00, /* ##..####........ */
+/* --- new character c (99) starting at offset 0x092c --- */
+ /*092c:*/ 12, 10, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0931:*/ 0x1f,0x00, /* ...#####........ */
+ /*0933:*/ 0x3f,0x80, /* ..#######....... */
+ /*0935:*/ 0x71,0xc0, /* .###...###...... */
+ /*0937:*/ 0x60,0xc0, /* .##.....##...... */
+ /*0939:*/ 0xc0,0x00, /* ##.............. */
+ /*093b:*/ 0xc0,0x00, /* ##.............. */
+ /*093d:*/ 0xc0,0x00, /* ##.............. */
+ /*093f:*/ 0xc0,0x00, /* ##.............. */
+ /*0941:*/ 0xc0,0x00, /* ##.............. */
+ /*0943:*/ 0xc0,0x00, /* ##.............. */
+ /*0945:*/ 0x60,0xc0, /* .##.....##...... */
+ /*0947:*/ 0x71,0xc0, /* .###...###...... */
+ /*0949:*/ 0x3f,0x80, /* ..#######....... */
+ /*094b:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character d (100) starting at offset 0x094d --- */
+ /*094d:*/ 14, 11, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0952:*/ 0x00,0x60, /* .........##..... */
+ /*0954:*/ 0x00,0x60, /* .........##..... */
+ /*0956:*/ 0x00,0x60, /* .........##..... */
+ /*0958:*/ 0x00,0x60, /* .........##..... */
+ /*095a:*/ 0x00,0x60, /* .........##..... */
+ /*095c:*/ 0x1e,0x60, /* ...####..##..... */
+ /*095e:*/ 0x3f,0x60, /* ..######.##..... */
+ /*0960:*/ 0x71,0xe0, /* .###...####..... */
+ /*0962:*/ 0x60,0xe0, /* .##.....###..... */
+ /*0964:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0966:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0968:*/ 0xc0,0x60, /* ##.......##..... */
+ /*096a:*/ 0xc0,0x60, /* ##.......##..... */
+ /*096c:*/ 0xc0,0x60, /* ##.......##..... */
+ /*096e:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0970:*/ 0x60,0xe0, /* .##.....###..... */
+ /*0972:*/ 0x71,0xe0, /* .###...####..... */
+ /*0974:*/ 0x3f,0x60, /* ..######.##..... */
+ /*0976:*/ 0x1e,0x60, /* ...####..##..... */
+/* --- new character e (101) starting at offset 0x0978 --- */
+ /*0978:*/ 13, 11, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*097d:*/ 0x0e,0x00, /* ....###......... */
+ /*097f:*/ 0x3f,0x80, /* ..#######....... */
+ /*0981:*/ 0x71,0xc0, /* .###...###...... */
+ /*0983:*/ 0x60,0xc0, /* .##.....##...... */
+ /*0985:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0987:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0989:*/ 0xff,0xe0, /* ###########..... */
+ /*098b:*/ 0xff,0xe0, /* ###########..... */
+ /*098d:*/ 0xc0,0x00, /* ##.............. */
+ /*098f:*/ 0xc0,0x00, /* ##.............. */
+ /*0991:*/ 0x60,0x60, /* .##......##..... */
+ /*0993:*/ 0x70,0xe0, /* .###....###..... */
+ /*0995:*/ 0x3f,0xc0, /* ..########...... */
+ /*0997:*/ 0x0f,0x00, /* ....####........ */
+/* --- new character f (102) starting at offset 0x0999 --- */
+ /*0999:*/ 8, 6, 19, 1, 0, /* width and bbox (w,h,x,y) */
+ /*099e:*/ 0x1c, /* ...###.. */
+ /*099f:*/ 0x3c, /* ..####.. */
+ /*09a0:*/ 0x30, /* ..##.... */
+ /*09a1:*/ 0x30, /* ..##.... */
+ /*09a2:*/ 0x30, /* ..##.... */
+ /*09a3:*/ 0xfc, /* ######.. */
+ /*09a4:*/ 0xfc, /* ######.. */
+ /*09a5:*/ 0x30, /* ..##.... */
+ /*09a6:*/ 0x30, /* ..##.... */
+ /*09a7:*/ 0x30, /* ..##.... */
+ /*09a8:*/ 0x30, /* ..##.... */
+ /*09a9:*/ 0x30, /* ..##.... */
+ /*09aa:*/ 0x30, /* ..##.... */
+ /*09ab:*/ 0x30, /* ..##.... */
+ /*09ac:*/ 0x30, /* ..##.... */
+ /*09ad:*/ 0x30, /* ..##.... */
+ /*09ae:*/ 0x30, /* ..##.... */
+ /*09af:*/ 0x30, /* ..##.... */
+ /*09b0:*/ 0x30, /* ..##.... */
+/* --- new character g (103) starting at offset 0x09b1 --- */
+ /*09b1:*/ 14, 11, 19, 1, -5, /* width and bbox (w,h,x,y) */
+ /*09b6:*/ 0x1e,0x60, /* ...####..##..... */
+ /*09b8:*/ 0x3f,0x60, /* ..######.##..... */
+ /*09ba:*/ 0x71,0xe0, /* .###...####..... */
+ /*09bc:*/ 0x60,0xe0, /* .##.....###..... */
+ /*09be:*/ 0xc0,0x60, /* ##.......##..... */
+ /*09c0:*/ 0xc0,0x60, /* ##.......##..... */
+ /*09c2:*/ 0xc0,0x60, /* ##.......##..... */
+ /*09c4:*/ 0xc0,0x60, /* ##.......##..... */
+ /*09c6:*/ 0xc0,0x60, /* ##.......##..... */
+ /*09c8:*/ 0xc0,0x60, /* ##.......##..... */
+ /*09ca:*/ 0x60,0xe0, /* .##.....###..... */
+ /*09cc:*/ 0x71,0xe0, /* .###...####..... */
+ /*09ce:*/ 0x3f,0x60, /* ..######.##..... */
+ /*09d0:*/ 0x1e,0x60, /* ...####..##..... */
+ /*09d2:*/ 0x00,0x60, /* .........##..... */
+ /*09d4:*/ 0xc0,0x60, /* ##.......##..... */
+ /*09d6:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*09d8:*/ 0x7f,0xc0, /* .#########...... */
+ /*09da:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character h (104) starting at offset 0x09dc --- */
+ /*09dc:*/ 13, 10, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*09e1:*/ 0xc0,0x00, /* ##.............. */
+ /*09e3:*/ 0xc0,0x00, /* ##.............. */
+ /*09e5:*/ 0xc0,0x00, /* ##.............. */
+ /*09e7:*/ 0xc0,0x00, /* ##.............. */
+ /*09e9:*/ 0xc0,0x00, /* ##.............. */
+ /*09eb:*/ 0xce,0x00, /* ##..###......... */
+ /*09ed:*/ 0xdf,0x80, /* ##.######....... */
+ /*09ef:*/ 0xf1,0x80, /* ####...##....... */
+ /*09f1:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*09f3:*/ 0xc0,0xc0, /* ##......##...... */
+ /*09f5:*/ 0xc0,0xc0, /* ##......##...... */
+ /*09f7:*/ 0xc0,0xc0, /* ##......##...... */
+ /*09f9:*/ 0xc0,0xc0, /* ##......##...... */
+ /*09fb:*/ 0xc0,0xc0, /* ##......##...... */
+ /*09fd:*/ 0xc0,0xc0, /* ##......##...... */
+ /*09ff:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0a01:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0a03:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0a05:*/ 0xc0,0xc0, /* ##......##...... */
+/* --- new character i (105) starting at offset 0x0a07 --- */
+ /*0a07:*/ 6, 2, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0a0c:*/ 0xc0, /* ##...... */
+ /*0a0d:*/ 0xc0, /* ##...... */
+ /*0a0e:*/ 0xc0, /* ##...... */
+ /*0a0f:*/ 0x00, /* ........ */
+ /*0a10:*/ 0x00, /* ........ */
+ /*0a11:*/ 0xc0, /* ##...... */
+ /*0a12:*/ 0xc0, /* ##...... */
+ /*0a13:*/ 0xc0, /* ##...... */
+ /*0a14:*/ 0xc0, /* ##...... */
+ /*0a15:*/ 0xc0, /* ##...... */
+ /*0a16:*/ 0xc0, /* ##...... */
+ /*0a17:*/ 0xc0, /* ##...... */
+ /*0a18:*/ 0xc0, /* ##...... */
+ /*0a19:*/ 0xc0, /* ##...... */
+ /*0a1a:*/ 0xc0, /* ##...... */
+ /*0a1b:*/ 0xc0, /* ##...... */
+ /*0a1c:*/ 0xc0, /* ##...... */
+ /*0a1d:*/ 0xc0, /* ##...... */
+ /*0a1e:*/ 0xc0, /* ##...... */
+/* --- new character j (106) starting at offset 0x0a1f --- */
+ /*0a1f:*/ 6, 4, 24, 0, -5, /* width and bbox (w,h,x,y) */
+ /*0a24:*/ 0x30, /* ..##.... */
+ /*0a25:*/ 0x30, /* ..##.... */
+ /*0a26:*/ 0x30, /* ..##.... */
+ /*0a27:*/ 0x00, /* ........ */
+ /*0a28:*/ 0x00, /* ........ */
+ /*0a29:*/ 0x30, /* ..##.... */
+ /*0a2a:*/ 0x30, /* ..##.... */
+ /*0a2b:*/ 0x30, /* ..##.... */
+ /*0a2c:*/ 0x30, /* ..##.... */
+ /*0a2d:*/ 0x30, /* ..##.... */
+ /*0a2e:*/ 0x30, /* ..##.... */
+ /*0a2f:*/ 0x30, /* ..##.... */
+ /*0a30:*/ 0x30, /* ..##.... */
+ /*0a31:*/ 0x30, /* ..##.... */
+ /*0a32:*/ 0x30, /* ..##.... */
+ /*0a33:*/ 0x30, /* ..##.... */
+ /*0a34:*/ 0x30, /* ..##.... */
+ /*0a35:*/ 0x30, /* ..##.... */
+ /*0a36:*/ 0x30, /* ..##.... */
+ /*0a37:*/ 0x30, /* ..##.... */
+ /*0a38:*/ 0x30, /* ..##.... */
+ /*0a39:*/ 0x30, /* ..##.... */
+ /*0a3a:*/ 0xf0, /* ####.... */
+ /*0a3b:*/ 0xe0, /* ###..... */
+/* --- new character k (107) starting at offset 0x0a3c --- */
+ /*0a3c:*/ 12, 10, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0a41:*/ 0xc0,0x00, /* ##.............. */
+ /*0a43:*/ 0xc0,0x00, /* ##.............. */
+ /*0a45:*/ 0xc0,0x00, /* ##.............. */
+ /*0a47:*/ 0xc0,0x00, /* ##.............. */
+ /*0a49:*/ 0xc0,0x00, /* ##.............. */
+ /*0a4b:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0a4d:*/ 0xc3,0x80, /* ##....###....... */
+ /*0a4f:*/ 0xc7,0x00, /* ##...###........ */
+ /*0a51:*/ 0xce,0x00, /* ##..###......... */
+ /*0a53:*/ 0xdc,0x00, /* ##.###.......... */
+ /*0a55:*/ 0xf8,0x00, /* #####........... */
+ /*0a57:*/ 0xfc,0x00, /* ######.......... */
+ /*0a59:*/ 0xce,0x00, /* ##..###......... */
+ /*0a5b:*/ 0xc6,0x00, /* ##...##......... */
+ /*0a5d:*/ 0xc7,0x00, /* ##...###........ */
+ /*0a5f:*/ 0xc3,0x80, /* ##....###....... */
+ /*0a61:*/ 0xc1,0x80, /* ##.....##....... */
+ /*0a63:*/ 0xc1,0xc0, /* ##.....###...... */
+ /*0a65:*/ 0xc0,0xc0, /* ##......##...... */
+/* --- new character l (108) starting at offset 0x0a67 --- */
+ /*0a67:*/ 6, 2, 19, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0a6c:*/ 0xc0, /* ##...... */
+ /*0a6d:*/ 0xc0, /* ##...... */
+ /*0a6e:*/ 0xc0, /* ##...... */
+ /*0a6f:*/ 0xc0, /* ##...... */
+ /*0a70:*/ 0xc0, /* ##...... */
+ /*0a71:*/ 0xc0, /* ##...... */
+ /*0a72:*/ 0xc0, /* ##...... */
+ /*0a73:*/ 0xc0, /* ##...... */
+ /*0a74:*/ 0xc0, /* ##...... */
+ /*0a75:*/ 0xc0, /* ##...... */
+ /*0a76:*/ 0xc0, /* ##...... */
+ /*0a77:*/ 0xc0, /* ##...... */
+ /*0a78:*/ 0xc0, /* ##...... */
+ /*0a79:*/ 0xc0, /* ##...... */
+ /*0a7a:*/ 0xc0, /* ##...... */
+ /*0a7b:*/ 0xc0, /* ##...... */
+ /*0a7c:*/ 0xc0, /* ##...... */
+ /*0a7d:*/ 0xc0, /* ##...... */
+ /*0a7e:*/ 0xc0, /* ##...... */
+/* --- new character m (109) starting at offset 0x0a7f --- */
+ /*0a7f:*/ 20, 16, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0a84:*/ 0xce,0x3c, /* ##..###...####.. */
+ /*0a86:*/ 0xff,0x7e, /* ########.######. */
+ /*0a88:*/ 0xe3,0xc7, /* ###...####...### */
+ /*0a8a:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a8c:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a8e:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a90:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a92:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a94:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a96:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a98:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a9a:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a9c:*/ 0xc1,0x83, /* ##.....##.....## */
+ /*0a9e:*/ 0xc1,0x83, /* ##.....##.....## */
+/* --- new character n (110) starting at offset 0x0aa0 --- */
+ /*0aa0:*/ 14, 10, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0aa5:*/ 0xce,0x00, /* ##..###......... */
+ /*0aa7:*/ 0xdf,0x80, /* ##.######....... */
+ /*0aa9:*/ 0xf1,0x80, /* ####...##....... */
+ /*0aab:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*0aad:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0aaf:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0ab1:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0ab3:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0ab5:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0ab7:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0ab9:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0abb:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0abd:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0abf:*/ 0xc0,0xc0, /* ##......##...... */
+/* --- new character o (111) starting at offset 0x0ac1 --- */
+ /*0ac1:*/ 13, 11, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0ac6:*/ 0x1f,0x00, /* ...#####........ */
+ /*0ac8:*/ 0x3f,0x80, /* ..#######....... */
+ /*0aca:*/ 0x71,0xc0, /* .###...###...... */
+ /*0acc:*/ 0x60,0xc0, /* .##.....##...... */
+ /*0ace:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0ad0:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0ad2:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0ad4:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0ad6:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0ad8:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0ada:*/ 0x60,0xc0, /* .##.....##...... */
+ /*0adc:*/ 0x71,0xc0, /* .###...###...... */
+ /*0ade:*/ 0x3f,0x80, /* ..#######....... */
+ /*0ae0:*/ 0x1f,0x00, /* ...#####........ */
+/* --- new character p (112) starting at offset 0x0ae2 --- */
+ /*0ae2:*/ 14, 11, 19, 2, -5, /* width and bbox (w,h,x,y) */
+ /*0ae7:*/ 0xcf,0x00, /* ##..####........ */
+ /*0ae9:*/ 0xdf,0x80, /* ##.######....... */
+ /*0aeb:*/ 0xf1,0xc0, /* ####...###...... */
+ /*0aed:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*0aef:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0af1:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0af3:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0af5:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0af7:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0af9:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0afb:*/ 0xe0,0xc0, /* ###.....##...... */
+ /*0afd:*/ 0xf1,0xc0, /* ####...###...... */
+ /*0aff:*/ 0xdf,0x80, /* ##.######....... */
+ /*0b01:*/ 0xcf,0x00, /* ##..####........ */
+ /*0b03:*/ 0xc0,0x00, /* ##.............. */
+ /*0b05:*/ 0xc0,0x00, /* ##.............. */
+ /*0b07:*/ 0xc0,0x00, /* ##.............. */
+ /*0b09:*/ 0xc0,0x00, /* ##.............. */
+ /*0b0b:*/ 0xc0,0x00, /* ##.............. */
+/* --- new character q (113) starting at offset 0x0b0d --- */
+ /*0b0d:*/ 14, 11, 19, 1, -5, /* width and bbox (w,h,x,y) */
+ /*0b12:*/ 0x1e,0x60, /* ...####..##..... */
+ /*0b14:*/ 0x3f,0x60, /* ..######.##..... */
+ /*0b16:*/ 0x71,0xe0, /* .###...####..... */
+ /*0b18:*/ 0x60,0xe0, /* .##.....###..... */
+ /*0b1a:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0b1c:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0b1e:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0b20:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0b22:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0b24:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0b26:*/ 0x60,0xe0, /* .##.....###..... */
+ /*0b28:*/ 0x71,0xe0, /* .###...####..... */
+ /*0b2a:*/ 0x3f,0x60, /* ..######.##..... */
+ /*0b2c:*/ 0x1e,0x60, /* ...####..##..... */
+ /*0b2e:*/ 0x00,0x60, /* .........##..... */
+ /*0b30:*/ 0x00,0x60, /* .........##..... */
+ /*0b32:*/ 0x00,0x60, /* .........##..... */
+ /*0b34:*/ 0x00,0x60, /* .........##..... */
+ /*0b36:*/ 0x00,0x60, /* .........##..... */
+/* --- new character r (114) starting at offset 0x0b38 --- */
+ /*0b38:*/ 9, 6, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0b3d:*/ 0xcc, /* ##..##.. */
+ /*0b3e:*/ 0xdc, /* ##.###.. */
+ /*0b3f:*/ 0xfc, /* ######.. */
+ /*0b40:*/ 0xe0, /* ###..... */
+ /*0b41:*/ 0xc0, /* ##...... */
+ /*0b42:*/ 0xc0, /* ##...... */
+ /*0b43:*/ 0xc0, /* ##...... */
+ /*0b44:*/ 0xc0, /* ##...... */
+ /*0b45:*/ 0xc0, /* ##...... */
+ /*0b46:*/ 0xc0, /* ##...... */
+ /*0b47:*/ 0xc0, /* ##...... */
+ /*0b48:*/ 0xc0, /* ##...... */
+ /*0b49:*/ 0xc0, /* ##...... */
+ /*0b4a:*/ 0xc0, /* ##...... */
+/* --- new character s (115) starting at offset 0x0b4b --- */
+ /*0b4b:*/ 12, 10, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0b50:*/ 0x3e,0x00, /* ..#####......... */
+ /*0b52:*/ 0x7f,0x80, /* .########....... */
+ /*0b54:*/ 0xe1,0xc0, /* ###....###...... */
+ /*0b56:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b58:*/ 0xc0,0x00, /* ##.............. */
+ /*0b5a:*/ 0xf8,0x00, /* #####........... */
+ /*0b5c:*/ 0x7f,0x00, /* .#######........ */
+ /*0b5e:*/ 0x0f,0x80, /* ....#####....... */
+ /*0b60:*/ 0x01,0xc0, /* .......###...... */
+ /*0b62:*/ 0x00,0xc0, /* ........##...... */
+ /*0b64:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b66:*/ 0xc1,0xc0, /* ##.....###...... */
+ /*0b68:*/ 0xff,0x80, /* #########....... */
+ /*0b6a:*/ 0x3f,0x00, /* ..######........ */
+/* --- new character t (116) starting at offset 0x0b6c --- */
+ /*0b6c:*/ 8, 6, 18, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0b71:*/ 0x30, /* ..##.... */
+ /*0b72:*/ 0x30, /* ..##.... */
+ /*0b73:*/ 0x30, /* ..##.... */
+ /*0b74:*/ 0x30, /* ..##.... */
+ /*0b75:*/ 0xfc, /* ######.. */
+ /*0b76:*/ 0xfc, /* ######.. */
+ /*0b77:*/ 0x30, /* ..##.... */
+ /*0b78:*/ 0x30, /* ..##.... */
+ /*0b79:*/ 0x30, /* ..##.... */
+ /*0b7a:*/ 0x30, /* ..##.... */
+ /*0b7b:*/ 0x30, /* ..##.... */
+ /*0b7c:*/ 0x30, /* ..##.... */
+ /*0b7d:*/ 0x30, /* ..##.... */
+ /*0b7e:*/ 0x30, /* ..##.... */
+ /*0b7f:*/ 0x30, /* ..##.... */
+ /*0b80:*/ 0x30, /* ..##.... */
+ /*0b81:*/ 0x3c, /* ..####.. */
+ /*0b82:*/ 0x1c, /* ...###.. */
+/* --- new character u (117) starting at offset 0x0b83 --- */
+ /*0b83:*/ 14, 10, 14, 2, 0, /* width and bbox (w,h,x,y) */
+ /*0b88:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b8a:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b8c:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b8e:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b90:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b92:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b94:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b96:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b98:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b9a:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0b9c:*/ 0xc1,0xc0, /* ##.....###...... */
+ /*0b9e:*/ 0x63,0xc0, /* .##...####...... */
+ /*0ba0:*/ 0x7e,0xc0, /* .######.##...... */
+ /*0ba2:*/ 0x1c,0xc0, /* ...###..##...... */
+/* --- new character v (118) starting at offset 0x0ba4 --- */
+ /*0ba4:*/ 13, 11, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0ba9:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0bab:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0bad:*/ 0xc0,0x60, /* ##.......##..... */
+ /*0baf:*/ 0x60,0xc0, /* .##.....##...... */
+ /*0bb1:*/ 0x60,0xc0, /* .##.....##...... */
+ /*0bb3:*/ 0x71,0xc0, /* .###...###...... */
+ /*0bb5:*/ 0x31,0x80, /* ..##...##....... */
+ /*0bb7:*/ 0x31,0x80, /* ..##...##....... */
+ /*0bb9:*/ 0x1b,0x00, /* ...##.##........ */
+ /*0bbb:*/ 0x1b,0x00, /* ...##.##........ */
+ /*0bbd:*/ 0x1b,0x00, /* ...##.##........ */
+ /*0bbf:*/ 0x0e,0x00, /* ....###......... */
+ /*0bc1:*/ 0x0e,0x00, /* ....###......... */
+ /*0bc3:*/ 0x0e,0x00, /* ....###......... */
+/* --- new character w (119) starting at offset 0x0bc5 --- */
+ /*0bc5:*/ 18, 18, 14, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0bca:*/ 0xc0,0xc0,0xc0, /* ##......##......##...... */
+ /*0bcd:*/ 0xc0,0xc0,0xc0, /* ##......##......##...... */
+ /*0bd0:*/ 0x61,0xe1,0x80, /* .##....####....##....... */
+ /*0bd3:*/ 0x61,0xe1,0x80, /* .##....####....##....... */
+ /*0bd6:*/ 0x61,0xe1,0x80, /* .##....####....##....... */
+ /*0bd9:*/ 0x31,0x23,0x00, /* ..##...#..#...##........ */
+ /*0bdc:*/ 0x33,0x33,0x00, /* ..##..##..##..##........ */
+ /*0bdf:*/ 0x33,0x33,0x00, /* ..##..##..##..##........ */
+ /*0be2:*/ 0x1b,0x36,0x00, /* ...##.##..##.##......... */
+ /*0be5:*/ 0x1a,0x16,0x00, /* ...##.#....#.##......... */
+ /*0be8:*/ 0x1e,0x1e,0x00, /* ...####....####......... */
+ /*0beb:*/ 0x0e,0x1c,0x00, /* ....###....###.......... */
+ /*0bee:*/ 0x0c,0x0c,0x00, /* ....##......##.......... */
+ /*0bf1:*/ 0x0c,0x0c,0x00, /* ....##......##.......... */
+/* --- new character x (120) starting at offset 0x0bf4 --- */
+ /*0bf4:*/ 12, 10, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0bf9:*/ 0xc0,0xc0, /* ##......##...... */
+ /*0bfb:*/ 0xe1,0xc0, /* ###....###...... */
+ /*0bfd:*/ 0x61,0x80, /* .##....##....... */
+ /*0bff:*/ 0x33,0x00, /* ..##..##........ */
+ /*0c01:*/ 0x3f,0x00, /* ..######........ */
+ /*0c03:*/ 0x1e,0x00, /* ...####......... */
+ /*0c05:*/ 0x0c,0x00, /* ....##.......... */
+ /*0c07:*/ 0x1e,0x00, /* ...####......... */
+ /*0c09:*/ 0x1e,0x00, /* ...####......... */
+ /*0c0b:*/ 0x33,0x00, /* ..##..##........ */
+ /*0c0d:*/ 0x73,0x80, /* .###..###....... */
+ /*0c0f:*/ 0x61,0x80, /* .##....##....... */
+ /*0c11:*/ 0xe1,0xc0, /* ###....###...... */
+ /*0c13:*/ 0xc0,0xc0, /* ##......##...... */
+/* --- new character y (121) starting at offset 0x0c15 --- */
+ /*0c15:*/ 13, 12, 19, 0, -5, /* width and bbox (w,h,x,y) */
+ /*0c1a:*/ 0xc0,0x30, /* ##........##.... */
+ /*0c1c:*/ 0xc0,0x30, /* ##........##.... */
+ /*0c1e:*/ 0x60,0x30, /* .##.......##.... */
+ /*0c20:*/ 0x70,0x60, /* .###.....##..... */
+ /*0c22:*/ 0x30,0x60, /* ..##.....##..... */
+ /*0c24:*/ 0x38,0xe0, /* ..###...###..... */
+ /*0c26:*/ 0x18,0xc0, /* ...##...##...... */
+ /*0c28:*/ 0x18,0xc0, /* ...##...##...... */
+ /*0c2a:*/ 0x0d,0x80, /* ....##.##....... */
+ /*0c2c:*/ 0x0d,0x80, /* ....##.##....... */
+ /*0c2e:*/ 0x07,0x80, /* .....####....... */
+ /*0c30:*/ 0x07,0x00, /* .....###........ */
+ /*0c32:*/ 0x03,0x00, /* ......##........ */
+ /*0c34:*/ 0x03,0x00, /* ......##........ */
+ /*0c36:*/ 0x06,0x00, /* .....##......... */
+ /*0c38:*/ 0x06,0x00, /* .....##......... */
+ /*0c3a:*/ 0x0c,0x00, /* ....##.......... */
+ /*0c3c:*/ 0x3c,0x00, /* ..####.......... */
+ /*0c3e:*/ 0x38,0x00, /* ..###........... */
+/* --- new character z (122) starting at offset 0x0c40 --- */
+ /*0c40:*/ 12, 10, 14, 1, 0, /* width and bbox (w,h,x,y) */
+ /*0c45:*/ 0xff,0xc0, /* ##########...... */
+ /*0c47:*/ 0xff,0xc0, /* ##########...... */
+ /*0c49:*/ 0x01,0x80, /* .......##....... */
+ /*0c4b:*/ 0x03,0x00, /* ......##........ */
+ /*0c4d:*/ 0x07,0x00, /* .....###........ */
+ /*0c4f:*/ 0x0e,0x00, /* ....###......... */
+ /*0c51:*/ 0x0c,0x00, /* ....##.......... */
+ /*0c53:*/ 0x1c,0x00, /* ...###.......... */
+ /*0c55:*/ 0x38,0x00, /* ..###........... */
+ /*0c57:*/ 0x30,0x00, /* ..##............ */
+ /*0c59:*/ 0x60,0x00, /* .##............. */
+ /*0c5b:*/ 0xe0,0x00, /* ###............. */
+ /*0c5d:*/ 0xff,0xc0, /* ##########...... */
+ /*0c5f:*/ 0xff,0xc0, /* ##########...... */
+/* --- new character braceleft (123) starting at offset 0x0c61 --- */
+ /*0c61:*/ 8, 6, 24, 1, -5, /* width and bbox (w,h,x,y) */
+ /*0c66:*/ 0x0c, /* ....##.. */
+ /*0c67:*/ 0x18, /* ...##... */
+ /*0c68:*/ 0x30, /* ..##.... */
+ /*0c69:*/ 0x30, /* ..##.... */
+ /*0c6a:*/ 0x30, /* ..##.... */
+ /*0c6b:*/ 0x30, /* ..##.... */
+ /*0c6c:*/ 0x30, /* ..##.... */
+ /*0c6d:*/ 0x30, /* ..##.... */
+ /*0c6e:*/ 0x30, /* ..##.... */
+ /*0c6f:*/ 0x30, /* ..##.... */
+ /*0c70:*/ 0x60, /* .##..... */
+ /*0c71:*/ 0xc0, /* ##...... */
+ /*0c72:*/ 0xc0, /* ##...... */
+ /*0c73:*/ 0x60, /* .##..... */
+ /*0c74:*/ 0x30, /* ..##.... */
+ /*0c75:*/ 0x30, /* ..##.... */
+ /*0c76:*/ 0x30, /* ..##.... */
+ /*0c77:*/ 0x30, /* ..##.... */
+ /*0c78:*/ 0x30, /* ..##.... */
+ /*0c79:*/ 0x30, /* ..##.... */
+ /*0c7a:*/ 0x30, /* ..##.... */
+ /*0c7b:*/ 0x30, /* ..##.... */
+ /*0c7c:*/ 0x18, /* ...##... */
+ /*0c7d:*/ 0x0c, /* ....##.. */
+/* --- new character bar (124) starting at offset 0x0c7e --- */
+ /*0c7e:*/ 6, 2, 24, 2, -5, /* width and bbox (w,h,x,y) */
+ /*0c83:*/ 0xc0, /* ##...... */
+ /*0c84:*/ 0xc0, /* ##...... */
+ /*0c85:*/ 0xc0, /* ##...... */
+ /*0c86:*/ 0xc0, /* ##...... */
+ /*0c87:*/ 0xc0, /* ##...... */
+ /*0c88:*/ 0xc0, /* ##...... */
+ /*0c89:*/ 0xc0, /* ##...... */
+ /*0c8a:*/ 0xc0, /* ##...... */
+ /*0c8b:*/ 0xc0, /* ##...... */
+ /*0c8c:*/ 0xc0, /* ##...... */
+ /*0c8d:*/ 0xc0, /* ##...... */
+ /*0c8e:*/ 0xc0, /* ##...... */
+ /*0c8f:*/ 0xc0, /* ##...... */
+ /*0c90:*/ 0xc0, /* ##...... */
+ /*0c91:*/ 0xc0, /* ##...... */
+ /*0c92:*/ 0xc0, /* ##...... */
+ /*0c93:*/ 0xc0, /* ##...... */
+ /*0c94:*/ 0xc0, /* ##...... */
+ /*0c95:*/ 0xc0, /* ##...... */
+ /*0c96:*/ 0xc0, /* ##...... */
+ /*0c97:*/ 0xc0, /* ##...... */
+ /*0c98:*/ 0xc0, /* ##...... */
+ /*0c99:*/ 0xc0, /* ##...... */
+ /*0c9a:*/ 0xc0, /* ##...... */
+/* --- new character braceright (125) starting at offset 0x0c9b --- */
+ /*0c9b:*/ 8, 6, 24, 1, -5, /* width and bbox (w,h,x,y) */
+ /*0ca0:*/ 0xc0, /* ##...... */
+ /*0ca1:*/ 0x60, /* .##..... */
+ /*0ca2:*/ 0x30, /* ..##.... */
+ /*0ca3:*/ 0x30, /* ..##.... */
+ /*0ca4:*/ 0x30, /* ..##.... */
+ /*0ca5:*/ 0x30, /* ..##.... */
+ /*0ca6:*/ 0x30, /* ..##.... */
+ /*0ca7:*/ 0x30, /* ..##.... */
+ /*0ca8:*/ 0x30, /* ..##.... */
+ /*0ca9:*/ 0x30, /* ..##.... */
+ /*0caa:*/ 0x18, /* ...##... */
+ /*0cab:*/ 0x0c, /* ....##.. */
+ /*0cac:*/ 0x0c, /* ....##.. */
+ /*0cad:*/ 0x18, /* ...##... */
+ /*0cae:*/ 0x30, /* ..##.... */
+ /*0caf:*/ 0x30, /* ..##.... */
+ /*0cb0:*/ 0x30, /* ..##.... */
+ /*0cb1:*/ 0x30, /* ..##.... */
+ /*0cb2:*/ 0x30, /* ..##.... */
+ /*0cb3:*/ 0x30, /* ..##.... */
+ /*0cb4:*/ 0x30, /* ..##.... */
+ /*0cb5:*/ 0x30, /* ..##.... */
+ /*0cb6:*/ 0x60, /* .##..... */
+ /*0cb7:*/ 0xc0, /* ##...... */
+/* --- new character asciitilde (126) starting at offset 0x0cb8 --- */
+ /*0cb8:*/ 14, 10, 4, 2, 5, /* width and bbox (w,h,x,y) */
+ /*0cbd:*/ 0x70,0xc0, /* .###....##...... */
+ /*0cbf:*/ 0xfc,0xc0, /* ######..##...... */
+ /*0cc1:*/ 0xcf,0xc0, /* ##..######...... */
+ /*0cc3:*/ 0xc3,0x80, /* ##....###....... */
+};
+static const uint16_t font_helvR24_offsets[] = {
+0x0000 /* space */,
+ 0x0006 /* exclam */,
+ 0x001e /* quotedbl */,
+ 0x0029 /* numbersign */,
+ 0x0050 /* dollar */,
+ 0x007f /* percent */,
+ 0x00ba /* ampersand */,
+ 0x00e3 /* quotesingle */,
+ 0x00ee /* parenleft */,
+ 0x010b /* parenright */,
+ 0x0128 /* asterisk */,
+ 0x0134 /* plus */,
+ 0x0151 /* comma */,
+ 0x015c /* hyphen */,
+ 0x0163 /* period */,
+ 0x016b /* slash */,
+ 0x0183 /* zero */,
+ 0x01ac /* one */,
+ 0x01c3 /* two */,
+ 0x01ec /* three */,
+ 0x0215 /* four */,
+ 0x023e /* five */,
+ 0x0267 /* six */,
+ 0x0290 /* seven */,
+ 0x02b9 /* eight */,
+ 0x02e2 /* nine */,
+ 0x030b /* colon */,
+ 0x031e /* semicolon */,
+ 0x0334 /* less */,
+ 0x0351 /* equal */,
+ 0x0362 /* greater */,
+ 0x037f /* question */,
+ 0x03aa /* at */,
+ 0x03f4 /* A */,
+ 0x041f /* B */,
+ 0x044a /* C */,
+ 0x0475 /* D */,
+ 0x04a0 /* E */,
+ 0x04cb /* F */,
+ 0x04f6 /* G */,
+ 0x0521 /* H */,
+ 0x054c /* I */,
+ 0x0564 /* J */,
+ 0x058f /* K */,
+ 0x05ba /* L */,
+ 0x05e5 /* M */,
+ 0x0623 /* N */,
+ 0x064e /* O */,
+ 0x0679 /* P */,
+ 0x06a4 /* Q */,
+ 0x06cf /* R */,
+ 0x06fa /* S */,
+ 0x0725 /* T */,
+ 0x0750 /* U */,
+ 0x077b /* V */,
+ 0x07a6 /* W */,
+ 0x07e4 /* X */,
+ 0x080f /* Y */,
+ 0x083a /* Z */,
+ 0x0865 /* bracketleft */,
+ 0x0882 /* backslash */,
+ 0x089a /* bracketright */,
+ 0x08b7 /* asciicircum */,
+ 0x08ce /* underscore */,
+ 0x08d7 /* grave */,
+ 0x08e0 /* a */,
+ 0x0901 /* b */,
+ 0x092c /* c */,
+ 0x094d /* d */,
+ 0x0978 /* e */,
+ 0x0999 /* f */,
+ 0x09b1 /* g */,
+ 0x09dc /* h */,
+ 0x0a07 /* i */,
+ 0x0a1f /* j */,
+ 0x0a3c /* k */,
+ 0x0a67 /* l */,
+ 0x0a7f /* m */,
+ 0x0aa0 /* n */,
+ 0x0ac1 /* o */,
+ 0x0ae2 /* p */,
+ 0x0b0d /* q */,
+ 0x0b38 /* r */,
+ 0x0b4b /* s */,
+ 0x0b6c /* t */,
+ 0x0b83 /* u */,
+ 0x0ba4 /* v */,
+ 0x0bc5 /* w */,
+ 0x0bf4 /* x */,
+ 0x0c15 /* y */,
+ 0x0c40 /* z */,
+ 0x0c61 /* braceleft */,
+ 0x0c7e /* bar */,
+ 0x0c9b /* braceright */,
+ 0x0cb8 /* asciitilde */,
+ 0xffff /* (no glyph) */
+};
+const struct fb_font font_helvR24 = {
+ .height = 27,
+ .ascent = 22,
+ .firstchar = 32, /* space */
+ .lastchar = 127, /* ? */
+ .chardata = font_helvR24_data,
+ .charoffs = font_helvR24_offsets,
+};
diff --git a/src/target/firmware/fb/symbols.c b/src/target/firmware/fb/symbols.c
new file mode 100644
index 00000000..e9eab82a
--- /dev/null
+++ b/src/target/firmware/fb/symbols.c
@@ -0,0 +1,113 @@
+#include <fb/font.h>
+static const uint8_t font_symbols_data[] = {
+/* @ battery - */
+ /*0000:*/ 3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0005:*/ 0x60, /* .##..... */
+ /*0006:*/ 0x40, /* .#...... */
+ /*0007:*/ 0x40, /* .#...... */
+ /*0008:*/ 0x40, /* .#...... */
+ /*0009:*/ 0x40, /* .#...... */
+ /*000a:*/ 0x40, /* .#...... */
+ /*000b:*/ 0x40, /* .#...... */
+ /*000c:*/ 0x60, /* .##..... */
+/* A battery empty */
+ /*000d:*/ 3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0012:*/ 0xe0, /* ###..... */
+ /*0013:*/ 0x00, /* ........ */
+ /*0014:*/ 0x00, /* ........ */
+ /*0015:*/ 0x00, /* ........ */
+ /*0016:*/ 0x00, /* ........ */
+ /*0017:*/ 0x00, /* ........ */
+ /*0018:*/ 0x00, /* ........ */
+ /*0019:*/ 0xe0, /* ###..... */
+/* B battery full */
+ /*001a:*/ 3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*001f:*/ 0xe0, /* ###..... */
+ /*0020:*/ 0x00, /* ........ */
+ /*0021:*/ 0xc0, /* ##...... */
+ /*0022:*/ 0xc0, /* ##...... */
+ /*0023:*/ 0xc0, /* ##...... */
+ /*0024:*/ 0xc0, /* ##...... */
+ /*0025:*/ 0x00, /* ........ */
+ /*0026:*/ 0xe0, /* ###..... */
+/* C battery + */
+ /*0027:*/ 3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*002c:*/ 0x80, /* #....... */
+ /*002d:*/ 0x80, /* #....... */
+ /*002e:*/ 0xc0, /* ##...... */
+ /*002f:*/ 0xc0, /* ##...... */
+ /*0030:*/ 0xc0, /* ##...... */
+ /*0031:*/ 0xc0, /* ##...... */
+ /*0032:*/ 0x80, /* #....... */
+ /*0033:*/ 0x80, /* #....... */
+/* D radiation left */
+ /*0034:*/ 3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0039:*/ 0x20, /* ..#..... */
+ /*003a:*/ 0x40, /* .#...... */
+ /*003b:*/ 0x20, /* ..#..... */
+ /*003c:*/ 0x00, /* ........ */
+ /*003d:*/ 0x00, /* ........ */
+ /*003e:*/ 0x00, /* ........ */
+ /*003f:*/ 0x00, /* ........ */
+ /*0040:*/ 0x00, /* ........ */
+/* E tower */
+ /*0041:*/ 5, 5, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0046:*/ 0x20, /* ..#..... */
+ /*0047:*/ 0x50, /* .#.#.... */
+ /*0048:*/ 0x20, /* ..#..... */
+ /*0049:*/ 0x20, /* ..#..... */
+ /*004a:*/ 0x50, /* .#.#.... */
+ /*004b:*/ 0x50, /* .#.#.... */
+ /*004c:*/ 0x88, /* #...#... */
+ /*004d:*/ 0xf8, /* #####... */
+/* F radiation right */
+ /*004e:*/ 3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0053:*/ 0x80, /* #....... */
+ /*0054:*/ 0x40, /* .#...... */
+ /*0055:*/ 0x80, /* #....... */
+ /*0056:*/ 0x00, /* ........ */
+ /*0057:*/ 0x00, /* ........ */
+ /*0058:*/ 0x00, /* ........ */
+ /*0059:*/ 0x00, /* ........ */
+ /*005a:*/ 0x00, /* ........ */
+/* G no radiation */
+ /*005b:*/ 3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*0060:*/ 0x00, /* ........ */
+ /*0061:*/ 0x00, /* ........ */
+ /*0062:*/ 0x00, /* ........ */
+ /*0063:*/ 0x00, /* ........ */
+ /*0064:*/ 0x00, /* ........ */
+ /*0065:*/ 0x00, /* ........ */
+ /*0066:*/ 0x00, /* ........ */
+ /*0067:*/ 0x00, /* ........ */
+/* H battery loaded */
+ /*0068:*/ 3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+ /*006d:*/ 0xe0, /* ###..... */
+ /*006e:*/ 0x00, /* ........ */
+ /*006f:*/ 0xe0, /* ###..... */
+ /*0070:*/ 0xe0, /* ###..... */
+ /*0071:*/ 0xe0, /* ###..... */
+ /*0072:*/ 0xe0, /* ###..... */
+ /*0073:*/ 0x00, /* ........ */
+ /*0074:*/ 0xe0, /* ###..... */
+};
+static const uint16_t font_symbols_offsets[] = {
+ 0x0000 /* '@' */,
+ 0x000d /* 'A' */,
+ 0x001a /* 'B' */,
+ 0x0027 /* 'C' */,
+ 0x0034 /* 'D' */,
+ 0x0041 /* 'E' */,
+ 0x004e /* 'F' */,
+ 0x005b /* 'G' */,
+ 0x0068 /* 'H' */,
+};
+const struct fb_font font_symbols = {
+ .height = 8,
+ .ascent = 8,
+ .firstchar = 64, /* '@' */
+ .lastchar = 72,
+ .chardata = font_symbols_data,
+ .charoffs = font_symbols_offsets,
+};
+
diff --git a/src/target/firmware/flash/cfi_flash.c b/src/target/firmware/flash/cfi_flash.c
new file mode 100644
index 00000000..8ecd2064
--- /dev/null
+++ b/src/target/firmware/flash/cfi_flash.c
@@ -0,0 +1,574 @@
+/* NOR Flash Driver for Intel 28F160C3 NOR flash */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <debug.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <memory.h>
+#include <defines.h>
+#include <flash/cfi_flash.h>
+
+/* XXX: strings must always be in ram */
+#if 0
+#define puts(...)
+#define printf(...)
+#endif
+
+/* global definitions */
+#define CFI_FLASH_MAX_ERASE_REGIONS 4
+
+/* structure of erase region descriptor */
+struct cfi_region {
+ uint16_t b_count;
+ uint16_t b_size;
+} __attribute__ ((packed));
+
+/* structure of cfi query response */
+struct cfi_query {
+ uint8_t qry[3];
+ uint16_t p_id;
+ uint16_t p_adr;
+ uint16_t a_id;
+ uint16_t a_adr;
+ uint8_t vcc_min;
+ uint8_t vcc_max;
+ uint8_t vpp_min;
+ uint8_t vpp_max;
+ uint8_t word_write_timeout_typ;
+ uint8_t buf_write_timeout_typ;
+ uint8_t block_erase_timeout_typ;
+ uint8_t chip_erase_timeout_typ;
+ uint8_t word_write_timeout_max;
+ uint8_t buf_write_timeout_max;
+ uint8_t block_erase_timeout_max;
+ uint8_t chip_erase_timeout_max;
+ uint8_t dev_size;
+ uint16_t interface_desc;
+ uint16_t max_buf_write_size;
+ uint8_t num_erase_regions;
+ struct cfi_region erase_regions[CFI_FLASH_MAX_ERASE_REGIONS];
+} __attribute__ ((packed));
+
+/* manufacturer ids */
+enum cfi_manuf {
+ CFI_MANUF_ST = 0x0020,
+ CFI_MANUF_INTEL = 0x0089,
+};
+
+/* algorithm ids */
+enum cfi_algo {
+ CFI_ALGO_INTEL_3 = 0x03
+};
+
+/* various command bytes */
+enum cfi_flash_cmd {
+ CFI_CMD_RESET = 0xff,
+ CFI_CMD_READ_ID = 0x90,
+ CFI_CMD_CFI = 0x98,
+ CFI_CMD_READ_STATUS = 0x70,
+ CFI_CMD_CLEAR_STATUS = 0x50,
+ CFI_CMD_WRITE = 0x40,
+ CFI_CMD_BLOCK_ERASE = 0x20,
+ CFI_CMD_ERASE_CONFIRM = 0xD0,
+ CFI_CMD_PROTECT = 0x60,
+};
+
+/* protection commands */
+enum flash_prot_cmd {
+ CFI_PROT_LOCK = 0x01,
+ CFI_PROT_UNLOCK = 0xD0,
+ CFI_PROT_LOCKDOWN = 0x2F
+};
+
+/* offsets from base */
+enum flash_offset {
+ CFI_OFFSET_MANUFACTURER_ID = 0x00,
+ CFI_OFFSET_DEVICE_ID = 0x01,
+ CFI_OFFSET_INTEL_PROTECTION = 0x81,
+ CFI_OFFSET_CFI_RESP = 0x10
+};
+
+/* offsets from block base */
+enum flash_block_offset {
+ CFI_OFFSET_BLOCK_LOCKSTATE = 0x02
+};
+
+/* status masks */
+enum flash_status {
+ CFI_STATUS_READY = 0x80,
+ CFI_STATUS_ERASE_SUSPENDED = 0x40,
+ CFI_STATUS_ERASE_ERROR = 0x20,
+ CFI_STATUS_PROGRAM_ERROR = 0x10,
+ CFI_STATUS_VPP_LOW = 0x08,
+ CFI_STATUS_PROGRAM_SUSPENDED = 0x04,
+ CFI_STATUS_LOCKED_ERROR = 0x02,
+ CFI_STATUS_RESERVED = 0x01
+};
+
+__ramtext
+static inline void flash_write_cmd(const void *base_addr, uint16_t cmd)
+{
+ writew(cmd, base_addr);
+}
+
+__ramtext
+static inline uint16_t flash_read16(const void *base_addr, uint32_t offset)
+{
+ return readw(base_addr + (offset << 1));
+}
+
+__ramtext
+static char flash_protected(uint32_t block_offset)
+{
+#ifdef CONFIG_FLASH_WRITE
+# ifdef CONFIG_FLASH_WRITE_LOADER
+ return 0;
+# else
+ return block_offset <= 0xFFFF;
+# endif
+#else
+ return 1;
+#endif
+}
+
+__ramtext
+flash_lock_t flash_block_getlock(flash_t * flash, uint32_t block_offset)
+{
+ const void *base_addr = flash->f_base;
+
+ uint8_t lockstate;
+ flash_write_cmd(base_addr, CFI_CMD_READ_ID);
+ lockstate =
+ flash_read16(base_addr,
+ (block_offset >> 1) + CFI_OFFSET_BLOCK_LOCKSTATE);
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ if (lockstate & 0x2) {
+ return FLASH_LOCKED_DOWN;
+ } else if (lockstate & 0x01) {
+ return FLASH_LOCKED;
+ } else {
+ return FLASH_UNLOCKED;
+ }
+}
+
+__ramtext
+int flash_block_unlock(flash_t * flash, uint32_t block_offset)
+{
+ const void *base_addr = flash->f_base;
+
+ if (block_offset >= flash->f_size) {
+ return -EINVAL;
+ }
+
+ if (flash_protected(block_offset)) {
+ return -EPERM;
+ }
+
+ printf("Unlocking block at 0x%08x, meaning %08x\n",
+ block_offset, base_addr + block_offset);
+
+ flash_write_cmd(base_addr, CFI_CMD_PROTECT);
+ flash_write_cmd(base_addr + block_offset, CFI_PROT_UNLOCK);
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ return 0;
+}
+
+__ramtext
+int flash_block_lock(flash_t * flash, uint32_t block_offset)
+{
+ const void *base_addr = flash->f_base;
+
+ if (block_offset >= flash->f_size) {
+ return -EINVAL;
+ }
+
+ printf("Locking block at 0x%08x\n", block_offset);
+
+ flash_write_cmd(base_addr, CFI_CMD_PROTECT);
+ flash_write_cmd(base_addr + block_offset, CFI_PROT_LOCK);
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ return 0;
+}
+
+__ramtext
+int flash_block_lockdown(flash_t * flash, uint32_t block_offset)
+{
+ const void *base_addr = flash->f_base;
+
+ if (block_offset >= flash->f_size) {
+ return -EINVAL;
+ }
+
+ printf("Locking down block at 0x%08x\n", block_offset);
+
+ flash_write_cmd(base_addr, CFI_CMD_PROTECT);
+ flash_write_cmd(base_addr + block_offset, CFI_PROT_LOCKDOWN);
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ return 0;
+}
+
+__ramtext
+int flash_block_erase(flash_t * flash, uint32_t block_offset)
+{
+ const void *base_addr = flash->f_base;
+
+ if (block_offset >= flash->f_size) {
+ return -EINVAL;
+ }
+
+ if (flash_protected(block_offset)) {
+ return -EPERM;
+ }
+
+ printf("Erasing block 0x%08x...", block_offset);
+
+ void *block_addr = ((uint8_t *) base_addr) + block_offset;
+
+ flash_write_cmd(base_addr, CFI_CMD_CLEAR_STATUS);
+
+ flash_write_cmd(block_addr, CFI_CMD_BLOCK_ERASE);
+ flash_write_cmd(block_addr, CFI_CMD_ERASE_CONFIRM);
+
+ flash_write_cmd(base_addr, CFI_CMD_READ_STATUS);
+ uint16_t status;
+ do {
+ status = flash_read16(base_addr, 0);
+ } while (!(status & CFI_STATUS_READY));
+
+ int res = 0;
+ if (status & CFI_STATUS_ERASE_ERROR) {
+ puts("error: ");
+ if (status & CFI_STATUS_VPP_LOW) {
+ puts("vpp insufficient\n");
+ res = -EFAULT;
+ } else if (status & CFI_STATUS_LOCKED_ERROR) {
+ puts("block is lock-protected\n");
+ res = -EPERM;
+ } else {
+ puts("unknown fault\n");
+ res = -EFAULT;
+ }
+ } else {
+ puts("done\n");
+ }
+
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ return res;
+
+}
+
+__ramtext
+int flash_program(flash_t * flash, uint32_t dst, void *src, uint32_t nbytes)
+{
+ const void *base_addr = flash->f_base;
+ int res = 0;
+ uint32_t i;
+
+ /* check destination bounds */
+ if (dst >= flash->f_size) {
+ return -EINVAL;
+ }
+ if (dst + nbytes > flash->f_size) {
+ return -EINVAL;
+ }
+
+ /* check alignments */
+ if (((uint32_t) src) % 2) {
+ return -EINVAL;
+ }
+ if (dst % 2) {
+ return -EINVAL;
+ }
+ if (nbytes % 2) {
+ return -EINVAL;
+ }
+
+ /* check permissions */
+ if (flash_protected(dst)) {
+ return -EPERM;
+ }
+
+ /* say something */
+ printf("Programming %u bytes to 0x%08x from 0x%p...", nbytes, dst, src);
+
+ /* clear status register */
+ flash_write_cmd(base_addr, CFI_CMD_CLEAR_STATUS);
+
+ /* write the words */
+ puts("writing...");
+ for (i = 0; i < nbytes; i += 2) {
+ uint16_t *src_addr = (uint16_t *) (src + i);
+ uint16_t *dst_addr = (uint16_t *) (base_addr + dst + i);
+
+ uint16_t data = *src_addr;
+
+ flash_write_cmd(dst_addr, CFI_CMD_WRITE);
+ flash_write_cmd(dst_addr, data);
+
+ flash_write_cmd(base_addr, CFI_CMD_READ_STATUS);
+ uint16_t status;
+ do {
+ status = flash_read16(base_addr, 0);
+ } while (!(status & CFI_STATUS_READY));
+
+ if (status & CFI_STATUS_PROGRAM_ERROR) {
+ puts("error: ");
+ if (status & CFI_STATUS_VPP_LOW) {
+ puts("vpp insufficient");
+ res = -EFAULT;
+ } else if (status & CFI_STATUS_LOCKED_ERROR) {
+ puts("block is lock-protected");
+ res = -EPERM;
+ } else {
+ puts("unknown fault");
+ res = -EFAULT;
+ }
+ goto err_reset;
+ }
+ }
+
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ /* verify the result */
+ puts("verifying...");
+ for (i = 0; i < nbytes; i += 2) {
+ uint16_t *src_addr = (uint16_t *) (src + i);
+ uint16_t *dst_addr = (uint16_t *) (base_addr + dst + i);
+ if (*src_addr != *dst_addr) {
+ puts("error: verification failed");
+ res = -EFAULT;
+ goto err;
+ }
+ }
+
+ puts("done\n");
+
+ return res;
+
+ err_reset:
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ err:
+ printf(" at offset 0x%x\n", i);
+
+ return res;
+}
+
+/* Internal: retrieve manufacturer and device id from id space */
+__ramtext
+static int get_id(void *base_addr,
+ uint16_t * manufacturer_id, uint16_t * device_id)
+{
+ flash_write_cmd(base_addr, CFI_CMD_READ_ID);
+
+ *manufacturer_id = flash_read16(base_addr, CFI_OFFSET_MANUFACTURER_ID);
+ *device_id = flash_read16(base_addr, CFI_OFFSET_DEVICE_ID);
+
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ return 0;
+}
+
+/* Internal: retrieve cfi query response data */
+__ramtext
+static int get_query(void *base_addr, struct cfi_query *query)
+{
+ int res = 0;
+ int i;
+
+ flash_write_cmd(base_addr, CFI_CMD_CFI);
+
+ for (i = 0; i < sizeof(struct cfi_query); i++) {
+ uint16_t byte =
+ flash_read16(base_addr, CFI_OFFSET_CFI_RESP + i);
+ *(((volatile unsigned char *)query) + i) = byte;
+ }
+
+ if (query->qry[0] != 'Q' || query->qry[1] != 'R' || query->qry[2] != 'Y') {
+ res = -ENOENT;
+ }
+
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ return res;
+}
+
+#if 0
+
+/* Internal: retrieve intel protection data */
+__ramtext
+static int get_intel_protection(void *base_addr,
+ uint16_t * lockp, uint8_t protp[8])
+{
+ int i;
+
+ /* check args */
+ if (!lockp) {
+ return -EINVAL;
+ }
+ if (!protp) {
+ return -EINVAL;
+ }
+
+ /* enter read id mode */
+ flash_write_cmd(base_addr, CFI_CMD_READ_ID);
+
+ /* get lock */
+ *lockp = flash_read16(base_addr, CFI_OFFSET_INTEL_PROTECTION);
+
+ /* get data */
+ for (i = 0; i < 8; i++) {
+ protp[i] = flash_read16(base_addr, CFI_OFFSET_INTEL_PROTECTION + 1 + i);
+ }
+
+ /* leave read id mode */
+ flash_write_cmd(base_addr, CFI_CMD_RESET);
+
+ return 0;
+}
+
+static void dump_intel_protection(uint16_t lock, uint8_t data[8])
+{
+ printf
+ (" protection lock 0x%4.4x data 0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+ lock, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+}
+
+static void dump_query_algorithms(struct cfi_query *qry)
+{
+ printf(" primary algorithm 0x%4.4x\n", qry->p_id);
+ printf(" primary extended query 0x%4.4x\n", qry->p_adr);
+ printf(" alternate algorithm 0x%4.4x\n", qry->a_id);
+ printf(" alternate extended query 0x%4.4x\n", qry->a_adr);
+}
+
+static void dump_query_timing(struct cfi_query *qry)
+{
+ uint32_t block_erase_typ = 1 << qry->block_erase_timeout_typ;
+ uint32_t block_erase_max =
+ (1 << qry->block_erase_timeout_max) * block_erase_typ;
+ uint32_t word_program_typ = 1 << qry->word_write_timeout_typ;
+ uint32_t word_program_max =
+ (1 << qry->word_write_timeout_max) * word_program_typ;
+ printf(" block erase typ %u ms\n", block_erase_typ);
+ printf(" block erase max %u ms\n", block_erase_max);
+ printf(" word program typ %u us\n", word_program_typ);
+ printf(" word program max %u us\n", word_program_max);
+}
+
+void flash_dump_info(flash_t * flash)
+{
+ int i;
+ printf("flash at 0x%p of %d bytes with %d regions\n",
+ flash->f_base, flash->f_size, flash->f_nregions);
+
+ uint16_t m_id, d_id;
+ if (get_id(flash->f_base, &m_id, &d_id)) {
+ puts(" failed to get id\n");
+ } else {
+ printf(" manufacturer 0x%4.4x device 0x%4.4x\n", m_id, d_id);
+ }
+
+ uint16_t plock;
+ uint8_t pdata[8];
+ if (get_intel_protection(flash->f_base, &plock, pdata)) {
+ puts(" failed to get protection data\n");
+ } else {
+ dump_intel_protection(plock, pdata);
+ }
+
+ struct cfi_query qry;
+ if (get_query(flash->f_base, &qry)) {
+ puts(" failed to get cfi query response\n");
+ } else {
+ dump_query_algorithms(&qry);
+ dump_query_timing(&qry);
+ }
+
+ for (i = 0; i < flash->f_nregions; i++) {
+ flash_region_t *fr = &flash->f_regions[i];
+ printf(" region %d: %d blocks of %d bytes at 0x%p\n",
+ i, fr->fr_bnum, fr->fr_bsize, fr->fr_base);
+ }
+}
+
+#endif
+
+__ramtext
+int flash_init(flash_t * flash, void *base_addr)
+{
+ int res;
+ unsigned u;
+ uint16_t m_id, d_id;
+ uint32_t base;
+ struct cfi_query qry;
+
+ /* retrieve and check manufacturer and device id */
+ res = get_id(base_addr, &m_id, &d_id);
+ if (res) {
+ return res;
+ }
+ if (m_id != CFI_MANUF_INTEL && m_id != CFI_MANUF_ST) {
+ return -ENOTSUP;
+ }
+
+ /* retrieve and check query response */
+ res = get_query(base_addr, &qry);
+ if (res) {
+ return res;
+ }
+ if (qry.p_id != CFI_ALGO_INTEL_3) {
+ /* we only support algo 3 */
+ return -ENOTSUP;
+ }
+ if (qry.num_erase_regions > FLASH_MAX_REGIONS) {
+ /* we have a hard limit on the number of regions */
+ return -ENOTSUP;
+ }
+
+ /* fill in basic information */
+ flash->f_base = base_addr;
+ flash->f_size = 1 << qry.dev_size;
+
+ /* determine number of erase regions */
+ flash->f_nregions = qry.num_erase_regions;
+
+ /* compute actual erase region info from cfi junk */
+ base = 0;
+ for (u = 0; u < flash->f_nregions; u++) {
+ flash_region_t *fr = &flash->f_regions[u];
+
+ fr->fr_base = (void *)base;
+ fr->fr_bnum = qry.erase_regions[u].b_count + 1;
+ fr->fr_bsize = qry.erase_regions[u].b_size * 256;
+
+ base += fr->fr_bnum * fr->fr_bsize;
+ }
+
+ return 0;
+}
diff --git a/src/target/firmware/include/abb/twl3025.h b/src/target/firmware/include/abb/twl3025.h
new file mode 100755
index 00000000..36406449
--- /dev/null
+++ b/src/target/firmware/include/abb/twl3025.h
@@ -0,0 +1,186 @@
+#ifndef _TWL3025_H
+#define _TWL3025_H
+
+#define PAGE(n) (n << 7)
+enum twl3025_reg {
+ VRPCCFG = PAGE(1) | 30,
+ VRPCDEV = PAGE(0) | 30,
+ VRPCMSK = PAGE(1) | 31,
+ VRPCMSKABB = PAGE(1) | 29,
+ VRPCSTS = PAGE(0) | 31,
+ /* Monitoring ADC Registers */
+ MADCTRL = PAGE(0) | 13,
+ MADCSTAT = PAGE(0) | 24,
+ VBATREG = PAGE(0) | 15,
+ VCHGREG = PAGE(0) | 16,
+ ICHGREG = PAGE(0) | 17,
+ VBKPREG = PAGE(0) | 18,
+ ADIN1REG = PAGE(0) | 19,
+ ADIN2REG = PAGE(0) | 20,
+ ADIN3REG = PAGE(0) | 21,
+ ADIN4REG = PAGE(0) | 22,
+ /* Clock Generator Registers */
+ TOGBR1 = PAGE(0) | 4,
+ TOGBR2 = PAGE(0) | 5,
+ PWDNRG = PAGE(1) | 9,
+ TAPCTRL = PAGE(1) | 19,
+ TAPREG = PAGE(1) | 20,
+ /* Automatic Frequency Control (AFC) Registers */
+ AUXAFC1 = PAGE(0) | 7,
+ AUXAFC2 = PAGE(0) | 8,
+ AFCCTLADD = PAGE(1) | 21,
+ AFCOUT = PAGE(1) | 22,
+ /* Automatic Power Control (APC) Registers */
+ APCDEL1 = PAGE(0) | 2,
+ APCDEL2 = PAGE(1) | 26,
+ AUXAPC = PAGE(0) | 9,
+ APCRAM = PAGE(0) | 10,
+ APCOFF = PAGE(0) | 11,
+ APCOUT = PAGE(1) | 12,
+ /* Auxiliary DAC Control Register */
+ AUXDAC = PAGE(0) | 12,
+ /* SimCard Control Register */
+ VRPCSIM = PAGE(1) | 23,
+ /* LED Driver Register */
+ AUXLED = PAGE(1) | 24,
+ /* Battery Charger Interface (BCI) Registers */
+ CHGREG = PAGE(0) | 25,
+ BCICTL1 = PAGE(0) | 28,
+ BCICTL2 = PAGE(0) | 29,
+ BCICONF = PAGE(1) | 13,
+ /* Interrupt and Bus Control (IBIC) Registers */
+ ITMASK = PAGE(0) | 28,
+ ITSTATREG = PAGE(0) | 27, /* both pages! */
+ PAGEREG = PAGE(0) | 1, /* both pages! */
+ /* Baseband Codec (BBC) Registers */
+ BULIOFF = PAGE(1) | 2,
+ BULQOFF = PAGE(1) | 3,
+ BULIDAC = PAGE(1) | 5,
+ BULQDAC = PAGE(1) | 4,
+ BULGCAL = PAGE(1) | 14,
+ BULDATA1 = PAGE(0) | 3, /* 16 words */
+ BBCTRL = PAGE(1) | 6,
+ /* Voiceband Codec (VBC) Registers */
+ VBCTRL1 = PAGE(1) | 8,
+ VBCTRL2 = PAGE(1) | 11,
+ VBPOP = PAGE(1) | 10,
+ VBUCTRL = PAGE(1) | 7,
+ VBDCTRL = PAGE(0) | 6,
+};
+#define BULDATA2 BULDATA1
+
+/* available ADC inputs on IOTA */
+enum twl3025_dac_inputs {/* === Signal ============================= */
+ MADC_VBAT=0, /* battery voltage / 4 */
+ MADC_VCHG=1, /* charger voltage / 5 */
+ MADC_ICHG=2, /* I-sense amp or CHGREG DAC output */
+ MADC_VBKP=3, /* backup battery voltage / 4 */
+ MADC_ADIN1=4, /* VADCID, sense battery type, not used */
+ MADC_ADIN2=5, /* Temperature sensor in Battery */
+ MADC_ADIN3=6, /* Mode_detect: sense 2.5mm jack insertion */
+ MADC_ADIN4=7, /* RITA: TEMP_SEN */
+ MADC_NUM_CHANNELS=8
+};
+
+enum madcstat_reg_bits { /* monitoring ADC status register */
+ ADCBUSY = 0x01 /* if set, a conversion is currently going on */
+};
+
+/* BCICTL1 register bits */
+enum bcictl1_reg_bits {
+ MESBAT = 1<<0, /* connect resistive divider for bat voltage */
+ DACNBUF = 1<<1, /* bypass DAC buffer */
+ THSENS0 = 1<<3, /* thermal sensor bias current (ADIN2), bit 0 */
+ THSENS1 = 1<<4, /* "" bit 1 */
+ THSENS2 = 1<<5, /* "" bit 2 */
+ THEN = 1<<6, /* enable thermal sensor bias current (ADIN1) */
+ TYPEN = 1<<7 /* enable bias current for battery type reading */
+};
+
+/* BCICTL1 register bits */
+enum bcictl2_reg_bits {
+ CHEN = 1<<0, /* enable charger */
+ CHIV = 1<<1, /* 1=constant current, 0=constant voltage */
+ CHBPASSPA=1<<2, /* full charging of the battery during pulse radio */
+ CLIB = 1<<3, /* calibrate I-to-V amp (short input pins) */
+ CHDISPA = 1<<4, /* disabel charging during pulse radio (???) */
+ LEDC = 1<<5, /* enable LED during charge */
+ CGAIN4 = 1<<6, /* if set, I-to-V amp gain is reduced from 10 to 4 */
+ PREOFF = 1<<7 /* disable battery precharge */
+};
+
+enum vrpcsts_reg_bits {
+ ONBSTS = 1<<0, /* button push switched on the mobile */
+ ONRSTS = 1<<1, /* RPWON terminal switched on the mobile */
+ ITWSTS = 1<<2, /* ITWAKEUP terminal switched on the mobile */
+ CHGSTS = 1<<3, /* plugging in charger has switched on the mobile */
+ ONREFLT= 1<<4, /* state of PWON terminal after debouncing */
+ ONMRFLT= 1<<5, /* state of RPWON terminal after debouncing */
+ CHGPRES= 1<<6 /* charger is connected */
+};
+
+enum togbr2_bits {
+ TOGBR2_KEEPR = (1 << 0), /* Clear KEEPON bit */
+ TOGBR2_KEEPS = (1 << 1), /* Set KEEPON bit */
+ TOGBR2_ACTR = (1 << 2), /* Dectivate MCLK */
+ TOGBR2_ACTS = (1 << 3), /* Activate MCLK */
+ TOGBR2_IBUFPTR1 = (1 << 4), /* Initialize pointer of burst buffer 1 */
+ TOGBR2_IBUFPTR2 = (1 << 5), /* Initialize pointer of burst buffer 2 */
+ TOGBR2_IAPCPTR = (1 << 6), /* Initialize pointer of APC RAM */
+};
+
+/* How a RAMP value is encoded */
+#define ABB_RAMP_VAL(up, down) ( ((down & 0x1F) << 5) | (up & 0x1F) )
+
+enum twl3025_unit {
+ TWL3025_UNIT_AFC,
+ TWL3025_UNIT_MAD,
+ TWL3025_UNIT_ADA,
+ TWL3025_UNIT_VDL,
+ TWL3025_UNIT_VUL,
+};
+
+void twl3025_init(void);
+void twl3025_reg_write(uint8_t reg, uint16_t data);
+uint16_t twl3025_reg_read(uint8_t reg);
+
+void twl3025_power_off(void);
+
+void twl3025_clk13m(int enable);
+
+void twl3025_unit_enable(enum twl3025_unit unit, int on);
+
+enum twl3025_tsp_bits {
+ BULON = 0x80,
+ BULCAL = 0x40,
+ BULENA = 0x20,
+ BDLON = 0x10,
+ BDLCAL = 0x08,
+ BDLENA = 0x04,
+ STARTADC = 0x02,
+};
+
+extern const uint16_t twl3025_default_ramp[16];
+
+/* Enqueue a TSP signal change via the TPU */
+void twl3025_tsp_write(uint8_t data);
+
+/* Enqueue a series of TSP commands in the TPU to (de)activate the downlink path */
+void twl3025_downlink(int on, int16_t at);
+
+/* Enqueue a series of TSP commands in the TPU to (de)activate the uplink path */
+void twl3025_uplink(int on, int16_t at);
+
+/* Update the AFC DAC value */
+void twl3025_afc_set(int16_t val);
+
+/* Get the AFC DAC value */
+int16_t twl3025_afc_get(void);
+
+/* Get the AFC DAC output value */
+uint8_t twl3025_afcout_get(void);
+
+/* Force a certain static AFC DAC output value */
+void twl3025_afcout_set(uint8_t val);
+
+#endif
diff --git a/src/target/firmware/include/arm.h b/src/target/firmware/include/arm.h
new file mode 100644
index 00000000..272c9c39
--- /dev/null
+++ b/src/target/firmware/include/arm.h
@@ -0,0 +1,7 @@
+#ifndef _ARM_H
+#define _ARM_H
+
+void arm_enable_interrupts(void);
+int arm_disable_interrupts(void);
+
+#endif
diff --git a/src/target/firmware/include/arpa/inet.h b/src/target/firmware/include/arpa/inet.h
new file mode 100644
index 00000000..9a4dd5c9
--- /dev/null
+++ b/src/target/firmware/include/arpa/inet.h
@@ -0,0 +1,2 @@
+/* we have this to make sure libosmocore uses our version of ntohl/htons */
+#include <byteorder.h>
diff --git a/src/target/firmware/include/asm/assembler.h b/src/target/firmware/include/asm/assembler.h
new file mode 100644
index 00000000..cd03e98d
--- /dev/null
+++ b/src/target/firmware/include/asm/assembler.h
@@ -0,0 +1,113 @@
+/*
+ * linux/include/asm-arm/assembler.h
+ *
+ * Copyright (C) 1996-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains arm architecture specific defines
+ * for the different processors.
+ *
+ * Do not include any C declarations in this file - it is included by
+ * assembler source.
+ */
+#ifndef __ASSEMBLY__
+#error "Only include this from assembly code"
+#endif
+
+#include <asm/ptrace.h>
+
+/*
+ * Endian independent macros for shifting bytes within registers.
+ */
+#ifndef __ARMEB__
+#define pull lsr
+#define push lsl
+#define get_byte_0 lsl #0
+#define get_byte_1 lsr #8
+#define get_byte_2 lsr #16
+#define get_byte_3 lsr #24
+#define put_byte_0 lsl #0
+#define put_byte_1 lsl #8
+#define put_byte_2 lsl #16
+#define put_byte_3 lsl #24
+#else
+#define pull lsl
+#define push lsr
+#define get_byte_0 lsr #24
+#define get_byte_1 lsr #16
+#define get_byte_2 lsr #8
+#define get_byte_3 lsl #0
+#define put_byte_0 lsl #24
+#define put_byte_1 lsl #16
+#define put_byte_2 lsl #8
+#define put_byte_3 lsl #0
+#endif
+
+#define PLD(code...)
+
+#define MODE_USR USR_MODE
+#define MODE_FIQ FIQ_MODE
+#define MODE_IRQ IRQ_MODE
+#define MODE_SVC SVC_MODE
+
+#define DEFAULT_FIQ MODE_FIQ
+
+/*
+ * LOADREGS - ldm with PC in register list (eg, ldmfd sp!, {pc})
+ */
+#ifdef __STDC__
+#define LOADREGS(cond, base, reglist...)\
+ ldm##cond base,reglist
+#else
+#define LOADREGS(cond, base, reglist...)\
+ ldm/**/cond base,reglist
+#endif
+
+/*
+ * Build a return instruction for this processor type.
+ */
+#define RETINSTR(instr, regs...)\
+ instr regs
+
+/*
+ * Enable and disable interrupts
+ */
+ .macro disable_irq
+ msr cpsr_c, #PSR_I_BIT | SVC_MODE
+ .endm
+
+ .macro enable_irq
+ msr cpsr_c, #SVC_MODE
+ .endm
+
+/*
+ * Save the current IRQ state and disable IRQs. Note that this macro
+ * assumes FIQs are enabled, and that the processor is in SVC mode.
+ */
+ .macro save_and_disable_irqs, oldcpsr
+ mrs \oldcpsr, cpsr
+ disable_irq
+ .endm
+
+/*
+ * Restore interrupt state previously stored in a register. We don't
+ * guarantee that this will preserve the flags.
+ */
+ .macro restore_irqs, oldcpsr
+ msr cpsr_c, \oldcpsr
+ .endm
+
+/*
+ * These two are used to save LR/restore PC over a user-based access.
+ * The old 26-bit architecture requires that we do. On 32-bit
+ * architecture, we can safely ignore this requirement.
+ */
+ .macro save_lr
+ .endm
+
+ .macro restore_pc
+ mov pc, lr
+ .endm
diff --git a/src/target/firmware/include/asm/atomic.h b/src/target/firmware/include/asm/atomic.h
new file mode 100644
index 00000000..19e8ce6f
--- /dev/null
+++ b/src/target/firmware/include/asm/atomic.h
@@ -0,0 +1,106 @@
+/*
+ * linux/include/asm-arm/atomic.h
+ *
+ * Copyright (C) 1996 Russell King.
+ * Copyright (C) 2002 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARM_ATOMIC_H
+#define __ASM_ARM_ATOMIC_H
+
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) { (i) }
+
+#define atomic_read(v) ((v)->counter)
+
+#include <asm/system.h>
+#include <asm/compiler.h>
+
+#define atomic_set(v,i) (((v)->counter) = (i))
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+ unsigned long flags;
+ int val;
+
+ local_irq_save(flags);
+ val = v->counter;
+ v->counter = val += i;
+ local_irq_restore(flags);
+
+ return val;
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+ unsigned long flags;
+ int val;
+
+ local_irq_save(flags);
+ val = v->counter;
+ v->counter = val -= i;
+ local_irq_restore(flags);
+
+ return val;
+}
+
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *addr &= ~mask;
+ local_irq_restore(flags);
+}
+
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+
+ c = atomic_read(v);
+ while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
+ c = old;
+ return c != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+#define atomic_add(i, v) (void) atomic_add_return(i, v)
+#define atomic_inc(v) (void) atomic_add_return(1, v)
+#define atomic_sub(i, v) (void) atomic_sub_return(i, v)
+#define atomic_dec(v) (void) atomic_sub_return(1, v)
+
+#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
+#define atomic_inc_return(v) (atomic_add_return(1, v))
+#define atomic_dec_return(v) (atomic_sub_return(1, v))
+#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
+
+#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)
+
+/* Atomic operations are already serializing on ARM */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+#endif
diff --git a/src/target/firmware/include/asm/bitops.h b/src/target/firmware/include/asm/bitops.h
new file mode 100644
index 00000000..337d800d
--- /dev/null
+++ b/src/target/firmware/include/asm/bitops.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright 1995, Russell King.
+ * Various bits and pieces copyrights include:
+ * Linus Torvalds (test_bit).
+ * Big endian support: Copyright 2001, Nicolas Pitre
+ * reworked by rmk.
+ *
+ * bit 0 is the LSB of an "unsigned long" quantity.
+ *
+ * Please note that the code in this file should never be included
+ * from user space. Many of these are not implemented in assembler
+ * since they would be too costly. Also, they require privileged
+ * instructions (which are not available from user mode) to ensure
+ * that they are atomic.
+ */
+
+#ifndef __ASM_ARM_BITOPS_H
+#define __ASM_ARM_BITOPS_H
+
+#include <asm/system.h>
+
+#define smp_mb__before_clear_bit() mb()
+#define smp_mb__after_clear_bit() mb()
+
+/*
+ * These functions are the basis of our bit ops.
+ *
+ * First, the atomic bitops. These use native endian.
+ */
+static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ *p |= mask;
+ local_irq_restore(flags);
+}
+
+static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ *p &= ~mask;
+ local_irq_restore(flags);
+}
+
+static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ *p ^= mask;
+ local_irq_restore(flags);
+}
+
+static inline int
+____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned int res;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ res = *p;
+ *p = res | mask;
+ local_irq_restore(flags);
+
+ return res & mask;
+}
+
+static inline int
+____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned int res;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ res = *p;
+ *p = res & ~mask;
+ local_irq_restore(flags);
+
+ return res & mask;
+}
+
+static inline int
+____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned int res;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ res = *p;
+ *p = res ^ mask;
+ local_irq_restore(flags);
+
+ return res & mask;
+}
+
+//#include <asm-generic/bitops/non-atomic.h>
+
+/*
+ * A note about Endian-ness.
+ * -------------------------
+ *
+ * When the ARM is put into big endian mode via CR15, the processor
+ * merely swaps the order of bytes within words, thus:
+ *
+ * ------------ physical data bus bits -----------
+ * D31 ... D24 D23 ... D16 D15 ... D8 D7 ... D0
+ * little byte 3 byte 2 byte 1 byte 0
+ * big byte 0 byte 1 byte 2 byte 3
+ *
+ * This means that reading a 32-bit word at address 0 returns the same
+ * value irrespective of the endian mode bit.
+ *
+ * Peripheral devices should be connected with the data bus reversed in
+ * "Big Endian" mode. ARM Application Note 61 is applicable, and is
+ * available from http://www.arm.com/.
+ *
+ * The following assumes that the data bus connectivity for big endian
+ * mode has been followed.
+ *
+ * Note that bit 0 is defined to be 32-bit word bit 0, not byte 0 bit 0.
+ */
+
+/*
+ * Little endian assembly bitops. nr = 0 -> byte 0 bit 0.
+ */
+extern void _set_bit_le(int nr, volatile unsigned long * p);
+extern void _clear_bit_le(int nr, volatile unsigned long * p);
+extern void _change_bit_le(int nr, volatile unsigned long * p);
+extern int _test_and_set_bit_le(int nr, volatile unsigned long * p);
+extern int _test_and_clear_bit_le(int nr, volatile unsigned long * p);
+extern int _test_and_change_bit_le(int nr, volatile unsigned long * p);
+extern int _find_first_zero_bit_le(const void * p, unsigned size);
+extern int _find_next_zero_bit_le(const void * p, int size, int offset);
+extern int _find_first_bit_le(const unsigned long *p, unsigned size);
+extern int _find_next_bit_le(const unsigned long *p, int size, int offset);
+
+/*
+ * Big endian assembly bitops. nr = 0 -> byte 3 bit 0.
+ */
+extern void _set_bit_be(int nr, volatile unsigned long * p);
+extern void _clear_bit_be(int nr, volatile unsigned long * p);
+extern void _change_bit_be(int nr, volatile unsigned long * p);
+extern int _test_and_set_bit_be(int nr, volatile unsigned long * p);
+extern int _test_and_clear_bit_be(int nr, volatile unsigned long * p);
+extern int _test_and_change_bit_be(int nr, volatile unsigned long * p);
+extern int _find_first_zero_bit_be(const void * p, unsigned size);
+extern int _find_next_zero_bit_be(const void * p, int size, int offset);
+extern int _find_first_bit_be(const unsigned long *p, unsigned size);
+extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
+
+/*
+ * The __* form of bitops are non-atomic and may be reordered.
+ */
+#define ATOMIC_BITOP_LE(name,nr,p) \
+ (__builtin_constant_p(nr) ? \
+ ____atomic_##name(nr, p) : \
+ _##name##_le(nr,p))
+
+#define ATOMIC_BITOP_BE(name,nr,p) \
+ (__builtin_constant_p(nr) ? \
+ ____atomic_##name(nr, p) : \
+ _##name##_be(nr,p))
+
+#define NONATOMIC_BITOP(name,nr,p) \
+ (____nonatomic_##name(nr, p))
+
+/*
+ * These are the little endian, atomic definitions.
+ */
+#define set_bit(nr,p) ATOMIC_BITOP_LE(set_bit,nr,p)
+#define clear_bit(nr,p) ATOMIC_BITOP_LE(clear_bit,nr,p)
+#define change_bit(nr,p) ATOMIC_BITOP_LE(change_bit,nr,p)
+#define test_and_set_bit(nr,p) ATOMIC_BITOP_LE(test_and_set_bit,nr,p)
+#define test_and_clear_bit(nr,p) ATOMIC_BITOP_LE(test_and_clear_bit,nr,p)
+#define test_and_change_bit(nr,p) ATOMIC_BITOP_LE(test_and_change_bit,nr,p)
+#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz)
+#define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off)
+#define find_first_bit(p,sz) _find_first_bit_le(p,sz)
+#define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off)
+
+#define WORD_BITOFF_TO_LE(x) ((x))
+
+#if 0
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/ffs.h>
+
+#include <asm-generic/bitops/fls64.h>
+
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
+#endif
+
+#define BITS_PER_LONG 32
+#define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
+
+static inline int test_bit(int nr, const volatile unsigned long *addr)
+{
+ return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+#endif /* _ARM_BITOPS_H */
diff --git a/src/target/firmware/include/asm/div64.h b/src/target/firmware/include/asm/div64.h
new file mode 100644
index 00000000..36826168
--- /dev/null
+++ b/src/target/firmware/include/asm/div64.h
@@ -0,0 +1,48 @@
+#ifndef __ASM_ARM_DIV64
+#define __ASM_ARM_DIV64
+
+#include <asm/system.h>
+
+/*
+ * The semantics of do_div() are:
+ *
+ * uint32_t do_div(uint64_t *n, uint32_t base)
+ * {
+ * uint32_t remainder = *n % base;
+ * *n = *n / base;
+ * return remainder;
+ * }
+ *
+ * In other words, a 64-bit dividend with a 32-bit divisor producing
+ * a 64-bit result and a 32-bit remainder. To accomplish this optimally
+ * we call a special __do_div64 helper with completely non standard
+ * calling convention for arguments and results (beware).
+ */
+
+#ifdef __ARMEB__
+#define __xh "r0"
+#define __xl "r1"
+#else
+#define __xl "r0"
+#define __xh "r1"
+#endif
+
+#define do_div(n,base) \
+({ \
+ register unsigned int __base asm("r4") = base; \
+ register unsigned long long __n asm("r0") = n; \
+ register unsigned long long __res asm("r2"); \
+ register unsigned int __rem asm(__xh); \
+ asm( __asmeq("%0", __xh) \
+ __asmeq("%1", "r2") \
+ __asmeq("%2", "r0") \
+ __asmeq("%3", "r4") \
+ "bl __do_div64" \
+ : "=r" (__rem), "=r" (__res) \
+ : "r" (__n), "r" (__base) \
+ : "ip", "lr", "cc"); \
+ n = __res; \
+ __rem; \
+})
+
+#endif
diff --git a/src/target/firmware/include/asm/linkage.h b/src/target/firmware/include/asm/linkage.h
new file mode 100644
index 00000000..ac1c900f
--- /dev/null
+++ b/src/target/firmware/include/asm/linkage.h
@@ -0,0 +1,18 @@
+#ifndef __ASM_LINKAGE_H
+#define __ASM_LINKAGE_H
+
+/* asm-arm/linkage.h */
+
+#define __ALIGN .align 0
+#define __ALIGN_STR ".align 0"
+
+/* linux/linkage.h */
+
+#define ALIGN __ALIGN
+
+#define ENTRY(name) \
+ .globl name; \
+ ALIGN; \
+ name:
+
+#endif
diff --git a/src/target/firmware/include/asm/ptrace.h b/src/target/firmware/include/asm/ptrace.h
new file mode 100644
index 00000000..f3a654e3
--- /dev/null
+++ b/src/target/firmware/include/asm/ptrace.h
@@ -0,0 +1,128 @@
+/*
+ * linux/include/asm-arm/ptrace.h
+ *
+ * Copyright (C) 1996-2003 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARM_PTRACE_H
+#define __ASM_ARM_PTRACE_H
+
+/*
+ * PSR bits
+ */
+#define USR26_MODE 0x00000000
+#define FIQ26_MODE 0x00000001
+#define IRQ26_MODE 0x00000002
+#define SVC26_MODE 0x00000003
+#define USR_MODE 0x00000010
+#define FIQ_MODE 0x00000011
+#define IRQ_MODE 0x00000012
+#define SVC_MODE 0x00000013
+#define ABT_MODE 0x00000017
+#define UND_MODE 0x0000001b
+#define SYSTEM_MODE 0x0000001f
+#define MODE32_BIT 0x00000010
+#define MODE_MASK 0x0000001f
+#define PSR_T_BIT 0x00000020
+#define PSR_F_BIT 0x00000040
+#define PSR_I_BIT 0x00000080
+#define PSR_J_BIT 0x01000000
+#define PSR_Q_BIT 0x08000000
+#define PSR_V_BIT 0x10000000
+#define PSR_C_BIT 0x20000000
+#define PSR_Z_BIT 0x40000000
+#define PSR_N_BIT 0x80000000
+#define PCMASK 0
+
+/*
+ * Groups of PSR bits
+ */
+#define PSR_f 0xff000000 /* Flags */
+#define PSR_s 0x00ff0000 /* Status */
+#define PSR_x 0x0000ff00 /* Extension */
+#define PSR_c 0x000000ff /* Control */
+
+#ifndef __ASSEMBLY__
+
+/*
+ * This struct defines the way the registers are stored on the
+ * stack during a system call. Note that sizeof(struct pt_regs)
+ * has to be a multiple of 8.
+ */
+struct pt_regs {
+ long uregs[18];
+};
+
+#define ARM_cpsr uregs[16]
+#define ARM_pc uregs[15]
+#define ARM_lr uregs[14]
+#define ARM_sp uregs[13]
+#define ARM_ip uregs[12]
+#define ARM_fp uregs[11]
+#define ARM_r10 uregs[10]
+#define ARM_r9 uregs[9]
+#define ARM_r8 uregs[8]
+#define ARM_r7 uregs[7]
+#define ARM_r6 uregs[6]
+#define ARM_r5 uregs[5]
+#define ARM_r4 uregs[4]
+#define ARM_r3 uregs[3]
+#define ARM_r2 uregs[2]
+#define ARM_r1 uregs[1]
+#define ARM_r0 uregs[0]
+#define ARM_ORIG_r0 uregs[17]
+
+#define user_mode(regs) \
+ (((regs)->ARM_cpsr & 0xf) == 0)
+
+#ifdef CONFIG_ARM_THUMB
+#define thumb_mode(regs) \
+ (((regs)->ARM_cpsr & PSR_T_BIT))
+#else
+#define thumb_mode(regs) (0)
+#endif
+
+#define processor_mode(regs) \
+ ((regs)->ARM_cpsr & MODE_MASK)
+
+#define interrupts_enabled(regs) \
+ (!((regs)->ARM_cpsr & PSR_I_BIT))
+
+#define fast_interrupts_enabled(regs) \
+ (!((regs)->ARM_cpsr & PSR_F_BIT))
+
+#define condition_codes(regs) \
+ ((regs)->ARM_cpsr & (PSR_V_BIT|PSR_C_BIT|PSR_Z_BIT|PSR_N_BIT))
+
+/* Are the current registers suitable for user mode?
+ * (used to maintain security in signal handlers)
+ */
+static inline int valid_user_regs(struct pt_regs *regs)
+{
+ if (user_mode(regs) &&
+ (regs->ARM_cpsr & (PSR_F_BIT|PSR_I_BIT)) == 0)
+ return 1;
+
+ /*
+ * Force CPSR to something logical...
+ */
+ regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | PSR_T_BIT | MODE32_BIT;
+
+ return 0;
+}
+
+#define pc_pointer(v) \
+ ((v) & ~PCMASK)
+
+#define instruction_pointer(regs) \
+ (pc_pointer((regs)->ARM_pc))
+
+#define profile_pc(regs) instruction_pointer(regs)
+
+#endif /* __ASSEMBLY__ */
+
+#endif
+
diff --git a/src/target/firmware/include/asm/swab.h b/src/target/firmware/include/asm/swab.h
new file mode 100644
index 00000000..4640e271
--- /dev/null
+++ b/src/target/firmware/include/asm/swab.h
@@ -0,0 +1,45 @@
+/*
+ * arch/arm/include/asm/byteorder.h
+ *
+ * ARM Endian-ness. In little endian mode, the data bus is connected such
+ * that byte accesses appear as:
+ * 0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31
+ * and word accesses (data or instruction) appear as:
+ * d0...d31
+ *
+ * When in big endian mode, byte accesses appear as:
+ * 0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7
+ * and word accesses (data or instruction) appear as:
+ * d0...d31
+ */
+#ifndef __ASM_ARM_SWAB_H
+#define __ASM_ARM_SWAB_H
+
+#include <stdint.h>
+#include <defines.h>
+
+static inline uint32_t __arch_swab32(uint32_t x)
+{
+ uint32_t t;
+
+#ifndef __thumb__
+ if (!__builtin_constant_p(x)) {
+ /*
+ * The compiler needs a bit of a hint here to always do the
+ * right thing and not screw it up to different degrees
+ * depending on the gcc version.
+ */
+ asm ("eor\t%0, %1, %1, ror #16" : "=r" (t) : "r" (x));
+ } else
+#endif
+ t = x ^ ((x << 16) | (x >> 16)); /* eor r1,r0,r0,ror #16 */
+
+ x = (x << 24) | (x >> 8); /* mov r0,r0,ror #8 */
+ t &= ~0x00FF0000; /* bic r1,r1,#0x00FF0000 */
+ x ^= (t >> 8); /* eor r0,r0,r1,lsr #8 */
+
+ return x;
+}
+#define __arch_swab32 __arch_swab32
+
+#endif
diff --git a/src/target/firmware/include/asm/system.h b/src/target/firmware/include/asm/system.h
new file mode 100644
index 00000000..3db0dc7a
--- /dev/null
+++ b/src/target/firmware/include/asm/system.h
@@ -0,0 +1,123 @@
+#ifndef __ASM_ARM_SYSTEM_H
+#define __ASM_ARM_SYSTEM_H
+
+/* Generic ARM7TDMI (ARMv4T) synchronisation primitives, mostly
+ * taken from Linux kernel source, licensed under GPL */
+
+#define local_irq_save(x) \
+ ({ \
+ unsigned long temp; \
+ (void) (&temp == &x); \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_save\n" \
+" orr %1, %0, #128\n" \
+" msr cpsr_c, %1" \
+ : "=r" (x), "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/* Save IRQ flags and disable FIQ + IRQ */
+#define local_firq_save(x) \
+ ({ \
+ unsigned long temp; \
+ (void) (&temp == &x); \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_firq_save\n" \
+" orr %1, %0, #0xC0\n" \
+" msr cpsr_c, %1" \
+ : "=r" (x), "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Enable IRQs
+ */
+#define local_irq_enable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_enable\n" \
+" bic %0, %0, #128\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Disable IRQs
+ */
+#define local_irq_disable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_disable\n" \
+" orr %0, %0, #128\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Enable FIQs
+ */
+#define local_fiq_enable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ stf\n" \
+" bic %0, %0, #64\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Disable FIQs
+ */
+#define local_fiq_disable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ clf\n" \
+" orr %0, %0, #64\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Save the current interrupt enable state.
+ */
+#define local_save_flags(x) \
+ ({ \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_save_flags" \
+ : "=r" (x) : : "memory", "cc"); \
+ })
+
+/*
+ * restore saved IRQ & FIQ state
+ */
+#define local_irq_restore(x) \
+ __asm__ __volatile__( \
+ "msr cpsr_c, %0 @ local_irq_restore\n" \
+ : \
+ : "r" (x) \
+ : "memory", "cc")
+
+#define irqs_disabled() \
+({ \
+ unsigned long flags; \
+ local_save_flags(flags); \
+ (int)(flags & PSR_I_BIT); \
+})
+
+#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
+
+#endif
diff --git a/src/target/firmware/include/battery/battery.h b/src/target/firmware/include/battery/battery.h
new file mode 100755
index 00000000..4270d7c6
--- /dev/null
+++ b/src/target/firmware/include/battery/battery.h
@@ -0,0 +1,37 @@
+#ifndef _BATTERY_BATTERY_H
+#define _BATTERY_BATTERY_H
+
+/* User-visible state of the battery charger.
+ *
+ * If CHG_CONNECTED, power is externally supplied to the mobile.
+ *
+ * If CHG_ENABLED, the charger will try to provide charge
+ * to the battery if needed, but this state might be switchable?
+ *
+ * BATTERY_CHARGING: Battery is not full, so a significant charging
+ * current (not trickle charge) is supplied.
+ *
+ * BATTERY_FAILURE: Overtemperature, overvoltage, ... if this bit
+ * is set, charging should be inhibited.
+ */
+
+
+enum battery_flags {
+ BATTERY_CHG_CONNECTED = 1 << 0, /* AC adapter is connected */
+ BATTERY_CHG_ENABLED = 1 << 1, /* if needed charger could charge */
+ BATTERY_CHARGING = 1 << 2, /* charger is actively charging */
+ BATTERY_FAILURE = 1 << 3, /* problem exists preventing charge */
+};
+
+struct battery_info {
+ enum battery_flags flags;
+ int charger_volt_mV; /* charger connection voltage */
+ int bat_volt_mV; /* battery terminal voltage */
+ int bat_chg_curr_mA; /* battery charging current */
+ int battery_percent; /* 0(empty) .. 100(full) */
+};
+
+extern struct battery_info
+battery_info;
+
+#endif
diff --git a/src/target/firmware/include/battery/compal_e88.h b/src/target/firmware/include/battery/compal_e88.h
new file mode 100644
index 00000000..c6c96f39
--- /dev/null
+++ b/src/target/firmware/include/battery/compal_e88.h
@@ -0,0 +1,15 @@
+#ifndef _BATTERY_COMPAL_E88_H
+#define _BATTERY_COMPAL_E88_H
+
+#include <stdint.h>
+#include <abb/twl3025.h>
+
+/* initialize the charger control loop on C123 */
+
+extern void
+battery_compal_e88_init();
+
+extern uint16_t
+compal_e88_madc[MADC_NUM_CHANNELS];
+
+#endif
diff --git a/src/target/firmware/include/board.h b/src/target/firmware/include/board.h
new file mode 100644
index 00000000..9783ef3e
--- /dev/null
+++ b/src/target/firmware/include/board.h
@@ -0,0 +1,8 @@
+#ifndef _BOARD_H
+#define _BOARD_H
+
+extern const char *target_board;
+
+void board_init(void);
+
+#endif /* _BOARD_H */
diff --git a/src/target/firmware/include/byteorder.h b/src/target/firmware/include/byteorder.h
new file mode 100644
index 00000000..41edb93d
--- /dev/null
+++ b/src/target/firmware/include/byteorder.h
@@ -0,0 +1,79 @@
+#ifndef _LINUX_BYTEORDER_LITTLE_ENDIAN_H
+#define _LINUX_BYTEORDER_LITTLE_ENDIAN_H
+
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+#ifndef __LITTLE_ENDIAN_BITFIELD
+#define __LITTLE_ENDIAN_BITFIELD
+#endif
+
+#include <stdint.h>
+#include <swab.h>
+
+#define __constant_htonl(x) ___constant_swab32(x)
+#define __constant_ntohl(x) ___constant_swab32(x)
+#define __constant_htons(x) ___constant_swab16(x)
+#define __constant_ntohs(x) ___constant_swab16(x)
+#define __constant_cpu_to_le64(x) (x)
+#define __constant_le64_to_cpu(x) (x)
+#define __constant_cpu_to_le32(x) (x)
+#define __constant_le32_to_cpu(x) (x)
+#define __constant_cpu_to_le16(x) (x)
+#define __constant_le16_to_cpu(x) (x)
+#define __constant_cpu_to_be64(x) ___constant_swab64(x)
+#define __constant_be64_to_cpu(x) ___constant_swab64(x)
+#define __constant_cpu_to_be32(x) ___constant_swab32(x)
+#define __constant_be32_to_cpu(x) ___constant_swab32(x)
+#define __constant_cpu_to_be16(x) ___constant_swab16(x)
+#define __constant_be16_to_cpu(x) ___constant_swab16(x)
+#define __cpu_to_le64(x) (x)
+#define __le64_to_cpu(x) (x)
+#define __cpu_to_le32(x) (x)
+#define __le32_to_cpu(x) (x)
+#define __cpu_to_le16(x) (x)
+#define __le16_to_cpu(x) (x)
+#define __cpu_to_be64(x) __swab64(x)
+#define __be64_to_cpu(x) __swab64(x)
+#define __cpu_to_be32(x) __swab32(x)
+#define __be32_to_cpu(x) __swab32(x)
+#define __cpu_to_be16(x) __swab16(x)
+#define __be16_to_cpu(x) __swab16(x)
+
+/* from include/linux/byteorder/generic.h */
+#define cpu_to_le64 __cpu_to_le64
+#define le64_to_cpu __le64_to_cpu
+#define cpu_to_le32 __cpu_to_le32
+#define le32_to_cpu __le32_to_cpu
+#define cpu_to_le16 __cpu_to_le16
+#define le16_to_cpu __le16_to_cpu
+#define cpu_to_be64 __cpu_to_be64
+#define be64_to_cpu __be64_to_cpu
+#define cpu_to_be32 __cpu_to_be32
+#define be32_to_cpu __be32_to_cpu
+#define cpu_to_be16 __cpu_to_be16
+#define be16_to_cpu __be16_to_cpu
+
+/*
+ * They have to be macros in order to do the constant folding
+ * correctly - if the argument passed into a inline function
+ * it is no longer constant according to gcc..
+ */
+
+#undef ntohl
+#undef ntohs
+#undef htonl
+#undef htons
+
+#define ___htonl(x) __cpu_to_be32(x)
+#define ___htons(x) __cpu_to_be16(x)
+#define ___ntohl(x) __be32_to_cpu(x)
+#define ___ntohs(x) __be16_to_cpu(x)
+
+#define htonl(x) ___htonl(x)
+#define ntohl(x) ___ntohl(x)
+#define htons(x) ___htons(x)
+#define ntohs(x) ___ntohs(x)
+
+
+#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */
diff --git a/src/target/firmware/include/calypso/backlight.h b/src/target/firmware/include/calypso/backlight.h
new file mode 100644
index 00000000..3a6abd55
--- /dev/null
+++ b/src/target/firmware/include/calypso/backlight.h
@@ -0,0 +1,10 @@
+#ifndef _CAL_BACKLIGHT_H
+#define _CAL_BACKLIGHT_H
+
+/* Switch backlight to PWL mode (or back) */
+void bl_mode_pwl(int on);
+
+/* Set the backlight level */
+void bl_level(uint8_t level);
+
+#endif /* CAL_BACKLIGHT_H */
diff --git a/src/target/firmware/include/calypso/buzzer.h b/src/target/firmware/include/calypso/buzzer.h
new file mode 100644
index 00000000..dcfd3a30
--- /dev/null
+++ b/src/target/firmware/include/calypso/buzzer.h
@@ -0,0 +1,34 @@
+#ifndef _CAL_BUZZER_H
+#define _CAL_BUZZER_H
+
+#define NOTE(n,oct) (n<<2 | (oct & 0x03))
+
+#define NOTE_E 0x00
+#define NOTE_DIS 0x01
+#define NOTE_D 0x02
+#define NOTE_CIS 0x03
+#define NOTE_C 0x04
+#define NOTE_H 0x05
+#define NOTE_AIS 0x06
+#define NOTE_A 0x07
+#define NOTE_GIS 0x08
+#define NOTE_G 0x09
+#define NOTE_FIS 0x0A
+#define NOTE_F 0x0B
+
+#define OCTAVE_5 OCTAVE(0x00)
+#define OCTAVE_4 OCTAVE(0x01)
+#define OCTAVE_3 OCTAVE(0x02)
+#define OCTAVE_2 OCTAVE(0x03)
+#define OCTAVE_1 OCTAVE(0x04)
+
+#define OCTAVE(m) (m>NOTE_C?m+1:m)
+
+/* Switch buzzer to PWT mode (or back) */
+void buzzer_mode_pwt(int on);
+/* Set the buzzer level */
+void buzzer_volume(uint8_t level);
+/* Set the buzzer note */
+void buzzer_note(uint8_t note);
+
+#endif /* _CAL_BUZZER_H */
diff --git a/src/target/firmware/include/calypso/clock.h b/src/target/firmware/include/calypso/clock.h
new file mode 100644
index 00000000..abcfde1d
--- /dev/null
+++ b/src/target/firmware/include/calypso/clock.h
@@ -0,0 +1,67 @@
+#ifndef _CALYPSO_CLK_H
+#define _CALYPSO_CLK_H
+
+#include <stdint.h>
+
+#define CALYPSO_PLL26_52_MHZ ((2 << 8) | 0)
+#define CALYPSO_PLL26_86_7_MHZ ((10 << 8) | 2)
+#define CALYPSO_PLL26_87_MHZ ((3 << 8) | 0)
+#define CALYPSO_PLL13_104_MHZ ((8 << 8) | 0)
+
+enum mclk_div {
+ _ARM_MCLK_DIV_1 = 0,
+ ARM_MCLK_DIV_1 = 1,
+ ARM_MCLK_DIV_2 = 2,
+ ARM_MCLK_DIV_3 = 3,
+ ARM_MCLK_DIV_4 = 4,
+ ARM_MCLK_DIV_5 = 5,
+ ARM_MCLK_DIV_6 = 6,
+ ARM_MCLK_DIV_7 = 7,
+ ARM_MCLK_DIV_1_5 = 0x80 | 1,
+ ARM_MCLK_DIV_2_5 = 0x80 | 2,
+};
+
+void calypso_clock_set(uint8_t vtcxo_div2, uint16_t inp, enum mclk_div mclk_div);
+void calypso_pll_set(uint16_t inp);
+void calypso_clk_dump(void);
+
+/* CNTL_RST */
+enum calypso_rst {
+ RESET_DSP = (1 << 1),
+ RESET_EXT = (1 << 2),
+ RESET_WDOG = (1 << 3),
+};
+
+void calypso_reset_set(enum calypso_rst calypso_rst, int active);
+int calypso_reset_get(enum calypso_rst);
+
+enum calypso_bank {
+ CALYPSO_nCS0 = 0,
+ CALYPSO_nCS1 = 2,
+ CALYPSO_nCS2 = 4,
+ CALYPSO_nCS3 = 6,
+ CALYPSO_nCS7 = 8,
+ CALYPSO_CS4 = 0xa,
+ CALYPSO_nCS6 = 0xc,
+};
+
+enum calypso_mem_width {
+ CALYPSO_MEM_8bit = 0,
+ CALYPSO_MEM_16bit = 1,
+ CALYPSO_MEM_32bit = 2,
+};
+
+void calypso_mem_cfg(enum calypso_bank bank, uint8_t ws,
+ enum calypso_mem_width width, int we);
+
+/* Enable or disable the internal bootrom mapped to 0x0000'0000 */
+void calypso_bootrom(int enable);
+
+/* Enable or disable the debug unit */
+void calypso_debugunit(int enable);
+
+/* configure the RHEA bus bridge[s] */
+void calypso_rhea_cfg(uint8_t fac0, uint8_t fac1, uint8_t timeout,
+ uint8_t ws_h, uint8_t ws_l, uint8_t w_en0, uint8_t w_en1);
+
+#endif /* _CALYPSO_CLK_H */
diff --git a/src/target/firmware/include/calypso/dma.h b/src/target/firmware/include/calypso/dma.h
new file mode 100644
index 00000000..00b9bde7
--- /dev/null
+++ b/src/target/firmware/include/calypso/dma.h
@@ -0,0 +1,6 @@
+#ifndef _CALYPSO_DMA_H
+#define _CALYPSO_DMA_H
+
+void dma_init(void);
+
+#endif /* _CALYPSO_DMA_H */
diff --git a/src/target/firmware/include/calypso/dsp.h b/src/target/firmware/include/calypso/dsp.h
new file mode 100644
index 00000000..e4801cbf
--- /dev/null
+++ b/src/target/firmware/include/calypso/dsp.h
@@ -0,0 +1,41 @@
+#ifndef _CALYPSO_DSP_H
+#define _CALYPSO_DSP_H
+
+#include <calypso/dsp_api.h>
+
+#define CAL_DSP_TGT_BB_LVL 80
+
+struct gsm_time;
+
+struct dsp_api {
+ T_NDB_MCU_DSP *ndb;
+ T_DB_DSP_TO_MCU *db_r;
+ T_DB_MCU_TO_DSP *db_w;
+ T_PARAM_MCU_DSP *param;
+ int r_page;
+ int w_page;
+ int r_page_used;
+ int frame_ctr;
+};
+
+extern struct dsp_api dsp_api;
+
+void dsp_power_on(void);
+void dsp_dump_version(void);
+void dsp_dump(void);
+void dsp_checksum_task(void);
+void dsp_api_memset(uint16_t *ptr, int octets);
+void dsp_memcpy_to_api(volatile uint16_t *dsp_buf, const uint8_t *mcu_buf, int n, int be);
+void dsp_memcpy_from_api(uint8_t *mcu_buf, const volatile uint16_t *dsp_buf, int n, int be);
+void dsp_load_afc_dac(uint16_t afc);
+void dsp_load_apc_dac(uint16_t apc);
+void dsp_load_tch_param(struct gsm_time *next_time,
+ uint8_t chan_mode, uint8_t chan_type, uint8_t chan_sub,
+ uint8_t tch_loop, uint8_t sync_tch, uint8_t tn);
+void dsp_load_ciph_param(int mode, uint8_t *key);
+void dsp_end_scenario(void);
+
+void dsp_load_rx_task(uint16_t task, uint8_t burst_id, uint8_t tsc);
+void dsp_load_tx_task(uint16_t task, uint8_t burst_id, uint8_t tsc);
+
+#endif
diff --git a/src/target/firmware/include/calypso/dsp_api.h b/src/target/firmware/include/calypso/dsp_api.h
new file mode 100644
index 00000000..f9751f37
--- /dev/null
+++ b/src/target/firmware/include/calypso/dsp_api.h
@@ -0,0 +1,1560 @@
+#ifndef _CAL_DSP_API_H
+#define _CAL_DSP_API_H
+
+/* This is a header file with structures imported from the TSM30 source code (l1_defty.h)
+ *
+ * As this header file only is a list of definitions and data structures, it is
+ * not ocnsidered to be a copyrightable work itself.
+ *
+ * Nonetheless, it might be good to rewrite it (without ugly typedefs!) */
+
+#if(L1_DYN_DSP_DWNLD == 1)
+ #include "l1_dyn_dwl_defty.h"
+#endif
+
+/* Include a header file that defines everything this l1_defty.h needs */
+#include "l1_environment.h"
+
+#define BASE_API_NDB 0xFFD001A8L /* 268 words */
+#define BASE_API_PARAM 0xFFD00862L /* 57 words */
+#define BASE_API_R_PAGE_0 0xFFD00050L /* 20 words */
+#define BASE_API_R_PAGE_1 0xFFD00078L /* 20 words */
+#define BASE_API_W_PAGE_0 0xFFD00000L /* 20 words */
+#define BASE_API_W_PAGE_1 0xFFD00028L /* 20 words */
+
+
+/***********************************************************/
+/* */
+/* Data structure for global info components. */
+/* */
+/***********************************************************/
+
+typedef struct
+{
+ API d_task_d; // (0) Downlink task command.
+ API d_burst_d; // (1) Downlink burst identifier.
+ API d_task_u; // (2) Uplink task command.
+ API d_burst_u; // (3) Uplink burst identifier.
+ API d_task_md; // (4) Downlink Monitoring (FB/SB) command.
+#if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ API d_background; // (5) Background tasks
+#else
+ API d_reserved; // (5) Reserved
+#endif
+ API d_debug; // (6) Debug/Acknowledge/general purpose word.
+ API d_task_ra; // (7) RA task command.
+ API d_fn; // (8) FN, in Rep. period and FN%104, used for TRAFFIC/TCH only.
+ // bit [0..7] -> b_fn_report, FN in the normalized reporting period.
+ // bit [8..15] -> b_fn_sid, FN % 104, used for SID positionning.
+ API d_ctrl_tch; // (9) Tch channel description.
+ // bit [0..3] -> b_chan_mode, channel mode.
+ // bit [4..5] -> b_chan_type, channel type.
+ // bit [6] -> reset SACCH
+ // bit [7] -> vocoder ON
+ // bit [8] -> b_sync_tch_ul, synchro. TCH/UL.
+ // bit [9] -> b_sync_tch_dl, synchro. TCH/DL.
+ // bit [10] -> b_stop_tch_ul, stop TCH/UL.
+ // bit [11] -> b_stop_tch_dl, stop TCH/DL.
+ // bit [12.13] -> b_tch_loop, tch loops A/B/C.
+ API hole; // (10) unused hole.
+
+#if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
+ API d_ctrl_abb; // (11) Bit field indicating the analog baseband register to send.
+ // bit [0] -> b_ramp: the ramp information(a_ramp[]) is located in NDB
+ // bit [1.2] -> unused
+ // bit [3] -> b_apcdel: delays-register in NDB
+ // bit [4] -> b_afc: freq control register in DB
+ // bit [5..15] -> unused
+#endif
+ API a_a5fn[2]; // (12..13) Encryption Frame number.
+ // word 0, bit [0..4] -> T2.
+ // word 0, bit [5..10] -> T3.
+ // word 1, bit [0..11] -> T1.
+ API d_power_ctl; // (14) Power level control.
+ API d_afc; // (15) AFC value (enabled by "b_afc" in "d_ctrl_TCM4400 or in d_ctrl_abb").
+ API d_ctrl_system; // (16) Controle Register for RESET/RESUME.
+ // bit [0..2] -> b_tsq, training sequence.
+ // bit [3] -> b_bcch_freq_ind, BCCH frequency indication.
+ // bit [15] -> b_task_abort, DSP task abort command.
+}
+T_DB_MCU_TO_DSP;
+
+typedef struct
+{
+ API d_task_d; // (0) Downlink task command.
+ API d_burst_d; // (1) Downlink burst identifier.
+ API d_task_u; // (2) Uplink task command.
+ API d_burst_u; // (3) Uplink burst identifier.
+ API d_task_md; // (4) Downlink Monitoring (FB/SB) task command.
+#if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ API d_background; // (5) Background tasks
+#else
+ API d_reserved; // (5) Reserved
+#endif
+ API d_debug; // (6) Debug/Acknowledge/general purpose word.
+ API d_task_ra; // (7) RA task command.
+
+#if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ API a_serv_demod[4]; // ( 8..11) Serv. cell demod. result, array of 4 words (D_TOA,D_PM,D_ANGLE,D_SNR).
+ API a_pm[3]; // (12..14) Power measurement results, array of 3 words.
+ API a_sch[5]; // (15..19) Header + SB information, array of 5 words.
+#else
+ API a_pm[3]; // ( 8..10) Power measurement results, array of 3 words.
+ API a_serv_demod[4]; // (11..14) Serv. cell demod. result, array of 4 words (D_TOA,D_PM,D_ANGLE,D_SNR).
+ API a_sch[5]; // (15..19) Header + SB information, array of 5 words.
+#endif
+}
+T_DB_DSP_TO_MCU;
+
+#if (DSP == 34) || (DSP == 35) || (DSP == 36) // NDB GSM
+ typedef struct
+ {
+ // MISC Tasks
+ API d_dsp_page;
+
+ // DSP status returned (DSP --> MCU).
+ API d_error_status;
+
+ // RIF control (MCU -> DSP).
+ API d_spcx_rif;
+
+ API d_tch_mode; // TCH mode register.
+ // bit [0..1] -> b_dai_mode.
+ // bit [2] -> b_dtx.
+
+ API d_debug1; // bit 0 at 1 enable dsp f_tx delay for Omega
+
+ API d_dsp_test;
+
+ // Words dedicated to Software version (DSP code + Patch)
+ API d_version_number1;
+ API d_version_number2;
+
+ API d_debug_ptr;
+ API d_debug_bk;
+
+ API d_pll_config;
+
+ // GSM/GPRS DSP Debug trace support
+ API p_debug_buffer;
+ API d_debug_buffer_size;
+ API d_debug_trace_type;
+
+ #if (W_A_DSP_IDLE3 == 1)
+ // DSP report its state: 0 run, 1 Idle1, 2 Idle2, 3 Idle3.
+ API d_dsp_state;
+ // 5 words are reserved for any possible mapping modification
+ API d_hole1_ndb[2];
+ #else
+ // 6 words are reserved for any possible mapping modification
+ API d_hole1_ndb[3];
+ #endif
+
+ #if (AMR == 1)
+ API p_debug_amr;
+ #else
+ API d_hole_debug_amr;
+ #endif
+
+ #if (CHIPSET == 12)
+ #if (DSP == 35) || (DSP == 36)
+ API d_hole2_ndb[1];
+ API d_mcsi_select;
+ #else
+ API d_hole2_ndb[2];
+ #endif
+ #else
+ API d_hole2_ndb[2];
+ #endif
+
+ // New words APCDEL1 and APCDEL2 for 2TX: TX/PRACH combinations
+ API d_apcdel1_bis;
+ API d_apcdel2_bis;
+
+
+ // New registers due to IOTA analog base band
+ API d_apcdel2;
+ API d_vbctrl2;
+ API d_bulgcal;
+
+ // Analog Based Band
+ API d_afcctladd;
+
+ API d_vbuctrl;
+ API d_vbdctrl;
+ API d_apcdel1;
+ API d_apcoff;
+ API d_bulioff;
+ API d_bulqoff;
+ API d_dai_onoff;
+ API d_auxdac;
+
+ #if (ANLG_FAM == 1)
+ API d_vbctrl;
+ #elif ((ANLG_FAM == 2) || (ANLG_FAM == 3))
+ API d_vbctrl1;
+ #endif
+
+ API d_bbctrl;
+
+ // Monitoring tasks control (MCU <- DSP)
+ // FB task
+ API d_fb_det; // FB detection result. (1 for FOUND).
+ API d_fb_mode; // Mode for FB detection algorithm.
+ API a_sync_demod[4]; // FB/SB demod. result, (D_TOA,D_PM,D_ANGLE,D_SNR).
+
+ // SB Task
+ API a_sch26[5]; // Header + SB information, array of 5 words.
+
+ API d_audio_gain_ul;
+ API d_audio_gain_dl;
+
+ // Controller of the melody E2 audio compressor
+ API d_audio_compressor_ctrl;
+
+ // AUDIO module
+ API d_audio_init;
+ API d_audio_status;
+
+ // Audio tasks
+ // TONES (MCU -> DSP)
+ API d_toneskb_init;
+ API d_toneskb_status;
+ API d_k_x1_t0;
+ API d_k_x1_t1;
+ API d_k_x1_t2;
+ API d_pe_rep;
+ API d_pe_off;
+ API d_se_off;
+ API d_bu_off;
+ API d_t0_on;
+ API d_t0_off;
+ API d_t1_on;
+ API d_t1_off;
+ API d_t2_on;
+ API d_t2_off;
+ API d_k_x1_kt0;
+ API d_k_x1_kt1;
+ API d_dur_kb;
+ API d_shiftdl;
+ API d_shiftul;
+
+ API d_aec_ctrl;
+
+ API d_es_level_api;
+ API d_mu_api;
+
+ // Melody Ringer module
+ API d_melo_osc_used;
+ API d_melo_osc_active;
+ API a_melo_note0[4];
+ API a_melo_note1[4];
+ API a_melo_note2[4];
+ API a_melo_note3[4];
+ API a_melo_note4[4];
+ API a_melo_note5[4];
+ API a_melo_note6[4];
+ API a_melo_note7[4];
+
+ // selection of the melody format
+ API d_melody_selection;
+
+ // Holes due to the format melody E1
+ API a_melo_holes[3];
+
+ // Speech Recognition module
+ API d_sr_status; // status of the DSP speech reco task
+ API d_sr_param; // paramters for the DSP speech reco task: OOV threshold.
+ API d_sr_bit_exact_test; // bit exact test
+ API d_sr_nb_words; // number of words used in the speech recognition task
+ API d_sr_db_level; // estimate voice level in dB
+ API d_sr_db_noise; // estimate noise in dB
+ API d_sr_mod_size; // size of the model
+ API a_n_best_words[4]; // array of the 4 best words
+ API a_n_best_score[8]; // array of the 4 best scores (each score is 32 bits length)
+
+ // Audio buffer
+ API a_dd_1[22]; // Header + DATA traffic downlink information, sub. chan. 1.
+ API a_du_1[22]; // Header + DATA traffic uplink information, sub. chan. 1.
+
+ // V42bis module
+ API d_v42b_nego0;
+ API d_v42b_nego1;
+ API d_v42b_control;
+ API d_v42b_ratio_ind;
+ API d_mcu_control;
+ API d_mcu_control_sema;
+
+ // Background tasks
+ API d_background_enable;
+ API d_background_abort;
+ API d_background_state;
+ API d_max_background;
+ API a_background_tasks[16];
+ API a_back_task_io[16];
+
+ // GEA module defined in l1p_deft.h (the following section is overlaid with GPRS NDB memory)
+ API d_gea_mode_ovly;
+ API a_gea_kc_ovly[4];
+
+#if (ANLG_FAM == 3)
+ // SYREN specific registers
+ API d_vbpop;
+ API d_vau_delay_init;
+ API d_vaud_cfg;
+ API d_vauo_onoff;
+ API d_vaus_vol;
+ API d_vaud_pll;
+ API d_hole3_ndb[1];
+#elif ((ANLG_FAM == 1) || (ANLG_FAM == 2))
+
+ API d_hole3_ndb[7];
+
+#endif
+
+ // word used for the init of USF threshold
+ API d_thr_usf_detect;
+
+ // Encryption module
+ API d_a5mode; // Encryption Mode.
+
+ API d_sched_mode_gprs_ovly;
+
+ // 7 words are reserved for any possible mapping modification
+ API d_hole4_ndb[5];
+
+ // Ramp definition for Omega device
+ API a_ramp[16];
+
+ // CCCH/SACCH downlink information...(!!)
+ API a_cd[15]; // Header + CCCH/SACCH downlink information.
+
+ // FACCH downlink information........(!!)
+ API a_fd[15]; // Header + FACCH downlink information.
+
+ // Traffic downlink data frames......(!!)
+ API a_dd_0[22]; // Header + DATA traffic downlink information, sub. chan. 0.
+
+ // CCCH/SACCH uplink information.....(!!)
+ API a_cu[15]; // Header + CCCH/SACCH uplink information.
+
+ // FACCH downlink information........(!!)
+ API a_fu[15]; // Header + FACCH uplink information
+
+ // Traffic downlink data frames......(!!)
+ API a_du_0[22]; // Header + DATA traffic uplink information, sub. chan. 0.
+
+ // Random access.....................(MCU -> DSP).
+ API d_rach; // RACH information.
+
+ //...................................(MCU -> DSP).
+ API a_kc[4]; // Encryption Key Code.
+
+ // Integrated Data Services module
+ API d_ra_conf;
+ API d_ra_act;
+ API d_ra_test;
+ API d_ra_statu;
+ API d_ra_statd;
+ API d_fax;
+ API a_data_buf_ul[21];
+ API a_data_buf_dl[37];
+
+ // GTT API mapping for DSP code 34 (for test only)
+ #if (L1_GTT == 1)
+ API d_tty_status;
+ API d_tty_detect_thres;
+ API d_ctm_detect_shift;
+ API d_tty_fa_thres;
+ API d_tty_mod_norm;
+ API d_tty_reset_buffer_ul;
+ API d_tty_loop_ctrl;
+ API p_tty_loop_buffer;
+ #else
+ API a_tty_holes[8];
+ #endif
+
+ API a_sr_holes0[414];
+
+ #if (L1_NEW_AEC)
+ // new AEC
+ API d_cont_filter;
+ API d_granularity_att;
+ API d_coef_smooth;
+ API d_es_level_max;
+ API d_fact_vad;
+ API d_thrs_abs;
+ API d_fact_asd_fil;
+ API d_fact_asd_mut;
+ API d_far_end_pow_h;
+ API d_far_end_pow_l;
+ API d_far_end_noise_h;
+ API d_far_end_noise_l;
+ #else
+ API a_new_aec_holes[12];
+ #endif // L1_NEW_AEC
+
+ // Speech recognition model
+ API a_sr_holes1[145];
+ API d_cport_init;
+ API d_cport_ctrl;
+ API a_cport_cfr[2];
+ API d_cport_tcl_tadt;
+ API d_cport_tdat;
+ API d_cport_tvs;
+ API d_cport_status;
+ API d_cport_reg_value;
+
+ API a_cport_holes[1011];
+
+ API a_model[1041];
+
+ // EOTD buffer
+#if (L1_EOTD==1)
+ API d_eotd_first;
+ API d_eotd_max;
+ API d_eotd_nrj_high;
+ API d_eotd_nrj_low;
+ API a_eotd_crosscor[18];
+#else
+ API a_eotd_holes[22];
+#endif
+ // AMR ver 1.0 buffers
+ API a_amr_config[4];
+ API a_ratscch_ul[6];
+ API a_ratscch_dl[6];
+ API d_amr_snr_est; // estimation of the SNR of the AMR speech block
+ #if (L1_VOICE_MEMO_AMR)
+ API d_amms_ul_voc;
+ #else
+ API a_voice_memo_amr_holes[1];
+ #endif
+ API d_thr_onset_afs; // thresh detection ONSET AFS
+ API d_thr_sid_first_afs; // thresh detection SID_FIRST AFS
+ API d_thr_ratscch_afs; // thresh detection RATSCCH AFS
+ API d_thr_update_afs; // thresh detection SID_UPDATE AFS
+ API d_thr_onset_ahs; // thresh detection ONSET AHS
+ API d_thr_sid_ahs; // thresh detection SID frames AHS
+ API d_thr_ratscch_marker;// thresh detection RATSCCH MARKER
+ API d_thr_sp_dgr; // thresh detection SPEECH DEGRADED/NO_DATA
+ API d_thr_soft_bits;
+ #if (MELODY_E2)
+ API d_melody_e2_osc_stop;
+ API d_melody_e2_osc_active;
+ API d_melody_e2_semaphore;
+ API a_melody_e2_osc[16][3];
+ API d_melody_e2_globaltimefactor;
+ API a_melody_e2_instrument_ptr[8];
+ API d_melody_e2_deltatime;
+
+ #if (AMR_THRESHOLDS_WORKAROUND)
+ API a_d_macc_thr_afs[8];
+ API a_d_macc_thr_ahs[6];
+ #else
+ API a_melody_e2_holes0[14];
+ #endif
+
+ API a_melody_e2_holes1[693];
+ API a_dsp_trace[SC_AUDIO_MELODY_E2_MAX_SIZE_OF_DSP_TRACE];
+ API a_melody_e2_instrument_wave[SC_AUDIO_MELODY_E2_MAX_SIZE_OF_INSTRUMENT];
+ #else
+ API d_holes[61];
+ #if (AMR_THRESHOLDS_WORKAROUND)
+ API a_d_macc_thr_afs[8];
+ API a_d_macc_thr_ahs[6];
+ #endif
+ #endif
+
+ }
+ T_NDB_MCU_DSP;
+#elif (DSP == 33) // NDB GSM
+ typedef struct
+ {
+ // MISC Tasks
+ API d_dsp_page;
+
+ // DSP status returned (DSP --> MCU).
+ API d_error_status;
+
+ // RIF control (MCU -> DSP).
+ API d_spcx_rif;
+
+ API d_tch_mode; // TCH mode register.
+ // bit [0..1] -> b_dai_mode.
+ // bit [2] -> b_dtx.
+
+ API d_debug1; // bit 0 at 1 enable dsp f_tx delay for Omega
+
+ API d_dsp_test;
+
+ // Words dedicated to Software version (DSP code + Patch)
+ API d_version_number1;
+ API d_version_number2;
+
+ API d_debug_ptr;
+ API d_debug_bk;
+
+ API d_pll_config;
+
+ // GSM/GPRS DSP Debug trace support
+ API p_debug_buffer;
+ API d_debug_buffer_size;
+ API d_debug_trace_type;
+
+ #if (W_A_DSP_IDLE3 == 1)
+ // DSP report its state: 0 run, 1 Idle1, 2 Idle2, 3 Idle3.
+ API d_dsp_state;
+ // 10 words are reserved for any possible mapping modification
+ API d_hole1_ndb[5];
+ #else
+ // 11 words are reserved for any possible mapping modification
+ API d_hole1_ndb[6];
+ #endif
+
+ // New words APCDEL1 and APCDEL2 for 2TX: TX/PRACH combinations
+ API d_apcdel1_bis;
+ API d_apcdel2_bis;
+
+
+ // New registers due to IOTA analog base band
+ API d_apcdel2;
+ API d_vbctrl2;
+ API d_bulgcal;
+
+ // Analog Based Band
+ API d_afcctladd;
+
+ API d_vbuctrl;
+ API d_vbdctrl;
+ API d_apcdel1;
+ API d_apcoff;
+ API d_bulioff;
+ API d_bulqoff;
+ API d_dai_onoff;
+ API d_auxdac;
+
+ #if (ANLG_FAM == 1)
+ API d_vbctrl;
+ #elif ((ANLG_FAM == 2) || (ANLG_FAM == 3))
+ API d_vbctrl1;
+ #endif
+
+ API d_bbctrl;
+
+ // Monitoring tasks control (MCU <- DSP)
+ // FB task
+ API d_fb_det; // FB detection result. (1 for FOUND).
+ API d_fb_mode; // Mode for FB detection algorithm.
+ API a_sync_demod[4]; // FB/SB demod. result, (D_TOA,D_PM,D_ANGLE,D_SNR).
+
+ // SB Task
+ API a_sch26[5]; // Header + SB information, array of 5 words.
+
+ API d_audio_gain_ul;
+ API d_audio_gain_dl;
+
+ // Controller of the melody E2 audio compressor
+ API d_audio_compressor_ctrl;
+
+ // AUDIO module
+ API d_audio_init;
+ API d_audio_status;
+
+ // Audio tasks
+ // TONES (MCU -> DSP)
+ API d_toneskb_init;
+ API d_toneskb_status;
+ API d_k_x1_t0;
+ API d_k_x1_t1;
+ API d_k_x1_t2;
+ API d_pe_rep;
+ API d_pe_off;
+ API d_se_off;
+ API d_bu_off;
+ API d_t0_on;
+ API d_t0_off;
+ API d_t1_on;
+ API d_t1_off;
+ API d_t2_on;
+ API d_t2_off;
+ API d_k_x1_kt0;
+ API d_k_x1_kt1;
+ API d_dur_kb;
+ API d_shiftdl;
+ API d_shiftul;
+
+ API d_aec_ctrl;
+
+ API d_es_level_api;
+ API d_mu_api;
+
+ // Melody Ringer module
+ API d_melo_osc_used;
+ API d_melo_osc_active;
+ API a_melo_note0[4];
+ API a_melo_note1[4];
+ API a_melo_note2[4];
+ API a_melo_note3[4];
+ API a_melo_note4[4];
+ API a_melo_note5[4];
+ API a_melo_note6[4];
+ API a_melo_note7[4];
+
+ // selection of the melody format
+ API d_melody_selection;
+
+ // Holes due to the format melody E1
+ API a_melo_holes[3];
+
+ // Speech Recognition module
+ API d_sr_status; // status of the DSP speech reco task
+ API d_sr_param; // paramters for the DSP speech reco task: OOV threshold.
+ API d_sr_bit_exact_test; // bit exact test
+ API d_sr_nb_words; // number of words used in the speech recognition task
+ API d_sr_db_level; // estimate voice level in dB
+ API d_sr_db_noise; // estimate noise in dB
+ API d_sr_mod_size; // size of the model
+ API a_n_best_words[4]; // array of the 4 best words
+ API a_n_best_score[8]; // array of the 4 best scores (each score is 32 bits length)
+
+ // Audio buffer
+ API a_dd_1[22]; // Header + DATA traffic downlink information, sub. chan. 1.
+ API a_du_1[22]; // Header + DATA traffic uplink information, sub. chan. 1.
+
+ // V42bis module
+ API d_v42b_nego0;
+ API d_v42b_nego1;
+ API d_v42b_control;
+ API d_v42b_ratio_ind;
+ API d_mcu_control;
+ API d_mcu_control_sema;
+
+ // Background tasks
+ API d_background_enable;
+ API d_background_abort;
+ API d_background_state;
+ API d_max_background;
+ API a_background_tasks[16];
+ API a_back_task_io[16];
+
+ // GEA module defined in l1p_deft.h (the following section is overlaid with GPRS NDB memory)
+ API d_gea_mode_ovly;
+ API a_gea_kc_ovly[4];
+
+ API d_hole3_ndb[8];
+
+ // Encryption module
+ API d_a5mode; // Encryption Mode.
+
+ API d_sched_mode_gprs_ovly;
+
+ // 7 words are reserved for any possible mapping modification
+ API d_hole4_ndb[5];
+
+ // Ramp definition for Omega device
+ API a_ramp[16];
+
+ // CCCH/SACCH downlink information...(!!)
+ API a_cd[15]; // Header + CCCH/SACCH downlink information.
+
+ // FACCH downlink information........(!!)
+ API a_fd[15]; // Header + FACCH downlink information.
+
+ // Traffic downlink data frames......(!!)
+ API a_dd_0[22]; // Header + DATA traffic downlink information, sub. chan. 0.
+
+ // CCCH/SACCH uplink information.....(!!)
+ API a_cu[15]; // Header + CCCH/SACCH uplink information.
+
+ // FACCH downlink information........(!!)
+ API a_fu[15]; // Header + FACCH uplink information
+
+ // Traffic downlink data frames......(!!)
+ API a_du_0[22]; // Header + DATA traffic uplink information, sub. chan. 0.
+
+ // Random access.....................(MCU -> DSP).
+ API d_rach; // RACH information.
+
+ //...................................(MCU -> DSP).
+ API a_kc[4]; // Encryption Key Code.
+
+ // Integrated Data Services module
+ API d_ra_conf;
+ API d_ra_act;
+ API d_ra_test;
+ API d_ra_statu;
+ API d_ra_statd;
+ API d_fax;
+ API a_data_buf_ul[21];
+ API a_data_buf_dl[37];
+
+ #if (L1_NEW_AEC)
+ // new AEC
+ API a_new_aec_holes[422];
+ API d_cont_filter;
+ API d_granularity_att;
+ API d_coef_smooth;
+ API d_es_level_max;
+ API d_fact_vad;
+ API d_thrs_abs;
+ API d_fact_asd_fil;
+ API d_fact_asd_mut;
+ API d_far_end_pow_h;
+ API d_far_end_pow_l;
+ API d_far_end_noise_h;
+ API d_far_end_noise_l;
+ #endif
+
+ // Speech recognition model
+ #if (L1_NEW_AEC)
+ API a_sr_holes[1165];
+ #else
+ API a_sr_holes[1599];
+ #endif // L1_NEW_AEC
+ API a_model[1041];
+
+ // EOTD buffer
+ #if (L1_EOTD==1)
+ API d_eotd_first;
+ API d_eotd_max;
+ API d_eotd_nrj_high;
+ API d_eotd_nrj_low;
+ API a_eotd_crosscor[18];
+ #else
+ API a_eotd_holes[22];
+ #endif
+
+ #if (MELODY_E2)
+ API a_melody_e2_holes0[27];
+ API d_melody_e2_osc_used;
+ API d_melody_e2_osc_active;
+ API d_melody_e2_semaphore;
+ API a_melody_e2_osc[16][3];
+ API d_melody_e2_globaltimefactor;
+ API a_melody_e2_instrument_ptr[8];
+ API a_melody_e2_holes1[708];
+ API a_dsp_trace[SC_AUDIO_MELODY_E2_MAX_SIZE_OF_DSP_TRACE];
+ API a_melody_e2_instrument_wave[SC_AUDIO_MELODY_E2_MAX_SIZE_OF_INSTRUMENT];
+ #endif
+ }
+ T_NDB_MCU_DSP;
+
+#elif ((DSP == 32) || (DSP == 31))
+ typedef struct
+ {
+ // Monitoring tasks control..........(MCU <- DSP)
+ API d_fb_det; // FB detection result. (1 for FOUND).
+ API d_fb_mode; // Mode for FB detection algorithm.
+ API a_sync_demod[4]; // FB/SB demod. result, (D_TOA,D_PM,D_ANGLE,D_SNR).
+
+ // CCCH/SACCH downlink information...(!!)
+ API a_cd[15]; // Header + CCCH/SACCH downlink information.
+
+ // FACCH downlink information........(!!)
+ API a_fd[15]; // Header + FACCH downlink information.
+
+ // Traffic downlink data frames......(!!)
+ API a_dd_0[22]; // Header + DATA traffic downlink information, sub. chan. 0.
+ API a_dd_1[22]; // Header + DATA traffic downlink information, sub. chan. 1.
+
+ // CCCH/SACCH uplink information.....(!!)
+ API a_cu[15]; // Header + CCCH/SACCH uplink information.
+
+ #if (SPEECH_RECO)
+ // FACCH downlink information........(!!)
+ API a_fu[3]; // Header + FACCH uplink information
+ // The size of this buffer is 15 word but some speech reco words
+ // are overlayer with this buffer. This is the reason why the size is 3 instead of 15.
+ API d_sr_status; // status of the DSP speech reco task
+ API d_sr_param; // paramters for the DSP speech reco task: OOV threshold.
+ API sr_hole1; // hole
+ API d_sr_bit_exact_test; // bit exact test
+ API d_sr_nb_words; // number of words used in the speech recognition task
+ API d_sr_db_level; // estimate voice level in dB
+ API d_sr_db_noise; // estimate noise in dB
+ API d_sr_mod_size; // size of the model
+ API sr_holes_1[4]; // hole
+ #else
+ // FACCH downlink information........(!!)
+ API a_fu[15]; // Header + FACCH uplink information
+ #endif
+
+ // Traffic uplink data frames........(!!)
+ API a_du_0[22]; // Header + DATA traffic uplink information, sub. chan. 0.
+ API a_du_1[22]; // Header + DATA traffic uplink information, sub. chan. 1.
+
+ // Random access.....................(MCU -> DSP).
+ API d_rach; // RACH information.
+
+ //...................................(MCU -> DSP).
+ API d_a5mode; // Encryption Mode.
+ API a_kc[4]; // Encryption Key Code.
+ API d_tch_mode; // TCH mode register.
+ // bit [0..1] -> b_dai_mode.
+ // bit [2] -> b_dtx.
+
+ // OMEGA...........................(MCU -> DSP).
+ #if ((ANLG_FAM == 1) || (ANLG_FAM == 2))
+ API a_ramp[16];
+ #if (MELODY_E1)
+ API d_melo_osc_used;
+ API d_melo_osc_active;
+ API a_melo_note0[4];
+ API a_melo_note1[4];
+ API a_melo_note2[4];
+ API a_melo_note3[4];
+ API a_melo_note4[4];
+ API a_melo_note5[4];
+ API a_melo_note6[4];
+ API a_melo_note7[4];
+ #if (DSP==31)
+ // selection of the melody format
+ API d_melody_selection;
+ API holes[9];
+ #else // DSP==32
+ API d_dco_type; // Tide
+ API p_start_IQ;
+ API d_level_off;
+ API d_dco_dbg;
+ API d_tide_resa;
+ API d_asynch_margin; // Perseus Asynch Audio Workaround
+ API hole[4];
+ #endif // DSP 32
+
+ #else // NO MELODY E1
+ #if (DSP==31)
+ // selection of the melody format
+ API d_melody_selection;
+ API holes[43]; // 43 unused holes.
+ #else // DSP==32
+ API holes[34]; // 34 unused holes.
+ API d_dco_type; // Tide
+ API p_start_IQ;
+ API d_level_off;
+ API d_dco_dbg;
+ API d_tide_resa;
+ API d_asynch_margin; // Perseus Asynch Audio Workaround
+ API hole[4];
+ #endif //DSP == 32
+ #endif // NO MELODY E1
+
+ API d_debug3;
+ API d_debug2;
+ API d_debug1; // bit 0 at 1 enable dsp f_tx delay for Omega
+ API d_afcctladd;
+ API d_vbuctrl;
+ API d_vbdctrl;
+ API d_apcdel1;
+ API d_aec_ctrl;
+ API d_apcoff;
+ API d_bulioff;
+ API d_bulqoff;
+ API d_dai_onoff;
+ API d_auxdac;
+
+ #if (ANLG_FAM == 1)
+ API d_vbctrl;
+ #elif (ANLG_FAM == 2)
+ API d_vbctrl1;
+ #endif
+
+ API d_bbctrl;
+ #else
+ #error DSPCODE not supported with given ANALOG
+ #endif //(ANALOG)1, 2
+ //...................................(MCU -> DSP).
+ API a_sch26[5]; // Header + SB information, array of 5 words.
+
+ // TONES.............................(MCU -> DSP)
+ API d_toneskb_init;
+ API d_toneskb_status;
+ API d_k_x1_t0;
+ API d_k_x1_t1;
+ API d_k_x1_t2;
+ API d_pe_rep;
+ API d_pe_off;
+ API d_se_off;
+ API d_bu_off;
+ API d_t0_on;
+ API d_t0_off;
+ API d_t1_on;
+ API d_t1_off;
+ API d_t2_on;
+ API d_t2_off;
+ API d_k_x1_kt0;
+ API d_k_x1_kt1;
+ API d_dur_kb;
+
+ // PLL...............................(MCU -> DSP).
+ API d_pll_clkmod1;
+ API d_pll_clkmod2;
+
+ // DSP status returned..........(DSP --> MCU).
+ API d_error_status;
+
+ // RIF control.......................(MCU -> DSP).
+ API d_spcx_rif;
+
+ API d_shiftdl;
+ API d_shiftul;
+
+ API p_saec_prog;
+ API p_aec_prog;
+ API p_spenh_prog;
+
+ API a_ovly[75];
+ API d_ra_conf;
+ API d_ra_act;
+ API d_ra_test;
+ API d_ra_statu;
+ API d_ra_statd;
+ API d_fax;
+ #if (SPEECH_RECO)
+ API a_data_buf_ul[3];
+ API a_n_best_words[4]; // array of the 4 best words
+ API a_n_best_score[8]; // array of the 4 best scores (each score is 32 bits length)
+ API sr_holes_2[6];
+ API a_data_buf_dl[37];
+
+ API a_hole[24];
+
+ API d_sched_mode_gprs_ovly;
+
+ API fir_holes1[384];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+ API d_audio_init;
+ API d_audio_status;
+
+ API a_model[1041]; // array of the speech reco model
+ #else
+ API a_data_buf_ul[21];
+ API a_data_buf_dl[37];
+
+ API a_hole[24];
+
+ API d_sched_mode_gprs_ovly;
+
+ API fir_holes1[384];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+ API d_audio_init;
+ API d_audio_status;
+
+#if (L1_EOTD ==1)
+ API a_eotd_hole[369];
+
+ API d_eotd_first;
+ API d_eotd_max;
+ API d_eotd_nrj_high;
+ API d_eotd_nrj_low;
+ API a_eotd_crosscor[18];
+#endif
+ #endif
+ }
+ T_NDB_MCU_DSP;
+
+
+#else // OTHER DSP CODE like 17
+
+typedef struct
+{
+ // Monitoring tasks control..........(MCU <- DSP)
+ API d_fb_det; // FB detection result. (1 for FOUND).
+ API d_fb_mode; // Mode for FB detection algorithm.
+ API a_sync_demod[4]; // FB/SB demod. result, (D_TOA,D_PM,D_ANGLE,D_SNR).
+
+ // CCCH/SACCH downlink information...(!!)
+ API a_cd[15]; // Header + CCCH/SACCH downlink information.
+
+ // FACCH downlink information........(!!)
+ API a_fd[15]; // Header + FACCH downlink information.
+
+ // Traffic downlink data frames......(!!)
+ #if (DATA14_4 == 0)
+ API a_dd_0[20]; // Header + DATA traffic downlink information, sub. chan. 0.
+ API a_dd_1[20]; // Header + DATA traffic downlink information, sub. chan. 1.
+ #endif
+ #if (DATA14_4 == 1)
+ API a_dd_0[22]; // Header + DATA traffic downlink information, sub. chan. 0.
+ API a_dd_1[22]; // Header + DATA traffic downlink information, sub. chan. 1.
+ #endif
+
+ // CCCH/SACCH uplink information.....(!!)
+ API a_cu[15]; // Header + CCCH/SACCH uplink information.
+
+ #if (SPEECH_RECO)
+ // FACCH downlink information........(!!)
+ API a_fu[3]; // Header + FACCH uplink information
+ // The size of this buffer is 15 word but some speech reco words
+ // are overlayer with this buffer. This is the reason why the size is 3 instead of 15.
+ API d_sr_status; // status of the DSP speech reco task
+ API d_sr_param; // paramters for the DSP speech reco task: OOV threshold.
+ API sr_hole1; // hole
+ API d_sr_bit_exact_test; // bit exact test
+ API d_sr_nb_words; // number of words used in the speech recognition task
+ API d_sr_db_level; // estimate voice level in dB
+ API d_sr_db_noise; // estimate noise in dB
+ API d_sr_mod_size; // size of the model
+ API sr_holes_1[4]; // hole
+ #else
+ // FACCH downlink information........(!!)
+ API a_fu[15]; // Header + FACCH uplink information
+ #endif
+
+ // Traffic uplink data frames........(!!)
+ #if (DATA14_4 == 0)
+ API a_du_0[20]; // Header + DATA traffic uplink information, sub. chan. 0.
+ API a_du_1[20]; // Header + DATA traffic uplink information, sub. chan. 1.
+ #endif
+ #if (DATA14_4 == 1)
+ API a_du_0[22]; // Header + DATA traffic uplink information, sub. chan. 0.
+ API a_du_1[22]; // Header + DATA traffic uplink information, sub. chan. 1.
+ #endif
+
+ // Random access.....................(MCU -> DSP).
+ API d_rach; // RACH information.
+
+ //...................................(MCU -> DSP).
+ API d_a5mode; // Encryption Mode.
+ API a_kc[4]; // Encryption Key Code.
+ API d_tch_mode; // TCH mode register.
+ // bit [0..1] -> b_dai_mode.
+ // bit [2] -> b_dtx.
+
+ // OMEGA...........................(MCU -> DSP).
+
+#if ((ANLG_FAM == 1) || (ANLG_FAM == 2))
+ API a_ramp[16];
+ #if (MELODY_E1)
+ API d_melo_osc_used;
+ API d_melo_osc_active;
+ API a_melo_note0[4];
+ API a_melo_note1[4];
+ API a_melo_note2[4];
+ API a_melo_note3[4];
+ API a_melo_note4[4];
+ API a_melo_note5[4];
+ API a_melo_note6[4];
+ API a_melo_note7[4];
+ #if (DSP == 17)
+ // selection of the melody format
+ API d_dco_type; // Tide
+ API p_start_IQ;
+ API d_level_off;
+ API d_dco_dbg;
+ API d_tide_resa;
+ API d_asynch_margin; // Perseus Asynch Audio Workaround
+ API hole[4];
+ #else
+ API d_melody_selection;
+ API holes[9];
+ #endif
+ #else // NO MELODY E1
+ // selection of the melody format
+ #if (DSP == 17)
+ API holes[34]; // 34 unused holes.
+ API d_dco_type; // Tide
+ API p_start_IQ;
+ API d_level_off;
+ API d_dco_dbg;
+ API d_tide_resa;
+ API d_asynch_margin; // Perseus Asynch Audio Workaround
+ API hole[4]
+ #else
+ // selection of the melody format
+ API d_melody_selection;
+ API holes[43]; // 43 unused holes.
+ #endif
+ #endif
+ API d_debug3;
+ API d_debug2;
+ API d_debug1; // bit 0 at 1 enable dsp f_tx delay for Omega
+ API d_afcctladd;
+ API d_vbuctrl;
+ API d_vbdctrl;
+ API d_apcdel1;
+ API d_aec_ctrl;
+ API d_apcoff;
+ API d_bulioff;
+ API d_bulqoff;
+ API d_dai_onoff;
+ API d_auxdac;
+ #if (ANLG_FAM == 1)
+ API d_vbctrl;
+ #elif (ANLG_FAM == 2)
+ API d_vbctrl1;
+ #endif
+ API d_bbctrl;
+
+ #else
+ #error DSPCODE not supported with given ANALOG
+ #endif //(ANALOG)1, 2
+ //...................................(MCU -> DSP).
+ API a_sch26[5]; // Header + SB information, array of 5 words.
+
+ // TONES.............................(MCU -> DSP)
+ API d_toneskb_init;
+ API d_toneskb_status;
+ API d_k_x1_t0;
+ API d_k_x1_t1;
+ API d_k_x1_t2;
+ API d_pe_rep;
+ API d_pe_off;
+ API d_se_off;
+ API d_bu_off;
+ API d_t0_on;
+ API d_t0_off;
+ API d_t1_on;
+ API d_t1_off;
+ API d_t2_on;
+ API d_t2_off;
+ API d_k_x1_kt0;
+ API d_k_x1_kt1;
+ API d_dur_kb;
+
+ // PLL...............................(MCU -> DSP).
+ API d_pll_clkmod1;
+ API d_pll_clkmod2;
+
+ // DSP status returned..........(DSP --> MCU).
+ API d_error_status;
+
+ // RIF control.......................(MCU -> DSP).
+ API d_spcx_rif;
+
+ API d_shiftdl;
+ API d_shiftul;
+
+ #if (AEC == 1)
+ // AEC control.......................(MCU -> DSP).
+ #if (VOC == FR_EFR)
+ API p_aec_init;
+ API p_aec_prog;
+ API p_spenh_init;
+ API p_spenh_prog;
+ #endif
+
+ #if (VOC == FR_HR_EFR)
+ API p_saec_prog;
+ API p_aec_prog;
+ API p_spenh_prog;
+ #endif
+ #endif
+
+ API a_ovly[75];
+ API d_ra_conf;
+ API d_ra_act;
+ API d_ra_test;
+ API d_ra_statu;
+ API d_ra_statd;
+ API d_fax;
+ #if (SPEECH_RECO)
+ API a_data_buf_ul[3];
+ API a_n_best_words[4]; // array of the 4 best words
+ API a_n_best_score[8]; // array of the 4 best scores (each score is 32 bits length)
+ API sr_holes_2[6];
+ API a_data_buf_dl[37];
+
+ API fir_holes1[409];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+ API d_audio_init;
+ API d_audio_status;
+ API a_model[1041]; // array of the speech reco model
+ #else
+ API a_data_buf_ul[21];
+ API a_data_buf_dl[37];
+
+ API fir_holes1[409];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+ API d_audio_init;
+ API d_audio_status;
+ #endif
+}
+T_NDB_MCU_DSP;
+#endif
+
+#if (DSP == 34) || (DSP == 35) || (DSP == 36)
+typedef struct
+{
+ API_SIGNED d_transfer_rate;
+
+ // Common GSM/GPRS
+ // These words specified the latencies to applies on some peripherics
+ API_SIGNED d_lat_mcu_bridge;
+ API_SIGNED d_lat_mcu_hom2sam;
+ API_SIGNED d_lat_mcu_bef_fast_access;
+ API_SIGNED d_lat_dsp_after_sam;
+
+ // DSP Start address
+ API_SIGNED d_gprs_install_address;
+
+ API_SIGNED d_misc_config;
+
+ API_SIGNED d_cn_sw_workaround;
+
+ API_SIGNED d_hole2_param[4];
+
+ //...................................Frequency Burst.
+ API_SIGNED d_fb_margin_beg;
+ API_SIGNED d_fb_margin_end;
+ API_SIGNED d_nsubb_idle;
+ API_SIGNED d_nsubb_dedic;
+ API_SIGNED d_fb_thr_det_iacq;
+ API_SIGNED d_fb_thr_det_track;
+ //...................................Demodulation.
+ API_SIGNED d_dc_off_thres;
+ API_SIGNED d_dummy_thres;
+ API_SIGNED d_dem_pond_gewl;
+ API_SIGNED d_dem_pond_red;
+
+ //...................................TCH Full Speech.
+ API_SIGNED d_maccthresh1;
+ API_SIGNED d_mldt;
+ API_SIGNED d_maccthresh;
+ API_SIGNED d_gu;
+ API_SIGNED d_go;
+ API_SIGNED d_attmax;
+ API_SIGNED d_sm;
+ API_SIGNED d_b;
+
+ // V42Bis module
+ API_SIGNED d_v42b_switch_hyst;
+ API_SIGNED d_v42b_switch_min;
+ API_SIGNED d_v42b_switch_max;
+ API_SIGNED d_v42b_reset_delay;
+
+ //...................................TCH Half Speech.
+ API_SIGNED d_ldT_hr;
+ API_SIGNED d_maccthresh_hr;
+ API_SIGNED d_maccthresh1_hr;
+ API_SIGNED d_gu_hr;
+ API_SIGNED d_go_hr;
+ API_SIGNED d_b_hr;
+ API_SIGNED d_sm_hr;
+ API_SIGNED d_attmax_hr;
+
+ //...................................TCH Enhanced FR Speech.
+ API_SIGNED c_mldt_efr;
+ API_SIGNED c_maccthresh_efr;
+ API_SIGNED c_maccthresh1_efr;
+ API_SIGNED c_gu_efr;
+ API_SIGNED c_go_efr;
+ API_SIGNED c_b_efr;
+ API_SIGNED c_sm_efr;
+ API_SIGNED c_attmax_efr;
+
+ //...................................CHED
+ API_SIGNED d_sd_min_thr_tchfs;
+ API_SIGNED d_ma_min_thr_tchfs;
+ API_SIGNED d_md_max_thr_tchfs;
+ API_SIGNED d_md1_max_thr_tchfs;
+
+ API_SIGNED d_sd_min_thr_tchhs;
+ API_SIGNED d_ma_min_thr_tchhs;
+ API_SIGNED d_sd_av_thr_tchhs;
+ API_SIGNED d_md_max_thr_tchhs;
+ API_SIGNED d_md1_max_thr_tchhs;
+
+ API_SIGNED d_sd_min_thr_tchefs;
+ API_SIGNED d_ma_min_thr_tchefs;
+ API_SIGNED d_md_max_thr_tchefs;
+ API_SIGNED d_md1_max_thr_tchefs;
+
+ API_SIGNED d_wed_fil_ini;
+ API_SIGNED d_wed_fil_tc;
+ API_SIGNED d_x_min;
+ API_SIGNED d_x_max;
+ API_SIGNED d_slope;
+ API_SIGNED d_y_min;
+ API_SIGNED d_y_max;
+ API_SIGNED d_wed_diff_threshold;
+ API_SIGNED d_mabfi_min_thr_tchhs;
+
+ // FACCH module
+ API_SIGNED d_facch_thr;
+
+ // IDS module
+ API_SIGNED d_max_ovsp_ul;
+ API_SIGNED d_sync_thres;
+ API_SIGNED d_idle_thres;
+ API_SIGNED d_m1_thres;
+ API_SIGNED d_max_ovsp_dl;
+ API_SIGNED d_gsm_bgd_mgt;
+
+ // FIR coefficients
+ API a_fir_holes[4];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+}
+T_PARAM_MCU_DSP;
+#elif (DSP == 33)
+typedef struct
+{
+ API_SIGNED d_transfer_rate;
+
+ // Common GSM/GPRS
+ // These words specified the latencies to applies on some peripherics
+ API_SIGNED d_lat_mcu_bridge;
+ API_SIGNED d_lat_mcu_hom2sam;
+ API_SIGNED d_lat_mcu_bef_fast_access;
+ API_SIGNED d_lat_dsp_after_sam;
+
+ // DSP Start address
+ API_SIGNED d_gprs_install_address;
+
+ API_SIGNED d_misc_config;
+
+ API_SIGNED d_cn_sw_workaround;
+
+ #if DCO_ALGO
+ API_SIGNED d_cn_dco_param;
+
+ API_SIGNED d_hole2_param[3];
+ #else
+ API_SIGNED d_hole2_param[4];
+ #endif
+
+ //...................................Frequency Burst.
+ API_SIGNED d_fb_margin_beg;
+ API_SIGNED d_fb_margin_end;
+ API_SIGNED d_nsubb_idle;
+ API_SIGNED d_nsubb_dedic;
+ API_SIGNED d_fb_thr_det_iacq;
+ API_SIGNED d_fb_thr_det_track;
+ //...................................Demodulation.
+ API_SIGNED d_dc_off_thres;
+ API_SIGNED d_dummy_thres;
+ API_SIGNED d_dem_pond_gewl;
+ API_SIGNED d_dem_pond_red;
+
+ //...................................TCH Full Speech.
+ API_SIGNED d_maccthresh1;
+ API_SIGNED d_mldt;
+ API_SIGNED d_maccthresh;
+ API_SIGNED d_gu;
+ API_SIGNED d_go;
+ API_SIGNED d_attmax;
+ API_SIGNED d_sm;
+ API_SIGNED d_b;
+
+ // V42Bis module
+ API_SIGNED d_v42b_switch_hyst;
+ API_SIGNED d_v42b_switch_min;
+ API_SIGNED d_v42b_switch_max;
+ API_SIGNED d_v42b_reset_delay;
+
+ //...................................TCH Half Speech.
+ API_SIGNED d_ldT_hr;
+ API_SIGNED d_maccthresh_hr;
+ API_SIGNED d_maccthresh1_hr;
+ API_SIGNED d_gu_hr;
+ API_SIGNED d_go_hr;
+ API_SIGNED d_b_hr;
+ API_SIGNED d_sm_hr;
+ API_SIGNED d_attmax_hr;
+
+ //...................................TCH Enhanced FR Speech.
+ API_SIGNED c_mldt_efr;
+ API_SIGNED c_maccthresh_efr;
+ API_SIGNED c_maccthresh1_efr;
+ API_SIGNED c_gu_efr;
+ API_SIGNED c_go_efr;
+ API_SIGNED c_b_efr;
+ API_SIGNED c_sm_efr;
+ API_SIGNED c_attmax_efr;
+
+ //...................................CHED
+ API_SIGNED d_sd_min_thr_tchfs;
+ API_SIGNED d_ma_min_thr_tchfs;
+ API_SIGNED d_md_max_thr_tchfs;
+ API_SIGNED d_md1_max_thr_tchfs;
+
+ API_SIGNED d_sd_min_thr_tchhs;
+ API_SIGNED d_ma_min_thr_tchhs;
+ API_SIGNED d_sd_av_thr_tchhs;
+ API_SIGNED d_md_max_thr_tchhs;
+ API_SIGNED d_md1_max_thr_tchhs;
+
+ API_SIGNED d_sd_min_thr_tchefs;
+ API_SIGNED d_ma_min_thr_tchefs;
+ API_SIGNED d_md_max_thr_tchefs;
+ API_SIGNED d_md1_max_thr_tchefs;
+
+ API_SIGNED d_wed_fil_ini;
+ API_SIGNED d_wed_fil_tc;
+ API_SIGNED d_x_min;
+ API_SIGNED d_x_max;
+ API_SIGNED d_slope;
+ API_SIGNED d_y_min;
+ API_SIGNED d_y_max;
+ API_SIGNED d_wed_diff_threshold;
+ API_SIGNED d_mabfi_min_thr_tchhs;
+
+ // FACCH module
+ API_SIGNED d_facch_thr;
+
+ // IDS module
+ API_SIGNED d_max_ovsp_ul;
+ API_SIGNED d_sync_thres;
+ API_SIGNED d_idle_thres;
+ API_SIGNED d_m1_thres;
+ API_SIGNED d_max_ovsp_dl;
+ API_SIGNED d_gsm_bgd_mgt;
+
+ // FIR coefficients
+ API a_fir_holes[4];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+}
+T_PARAM_MCU_DSP;
+
+#else
+
+typedef struct
+{
+ //...................................Frequency Burst.
+ API_SIGNED d_nsubb_idle;
+ API_SIGNED d_nsubb_dedic;
+ API_SIGNED d_fb_thr_det_iacq;
+ API_SIGNED d_fb_thr_det_track;
+ //...................................Demodulation.
+ API_SIGNED d_dc_off_thres;
+ API_SIGNED d_dummy_thres;
+ API_SIGNED d_dem_pond_gewl;
+ API_SIGNED d_dem_pond_red;
+ API_SIGNED hole[1];
+ API_SIGNED d_transfer_rate;
+ //...................................TCH Full Speech.
+ API_SIGNED d_maccthresh1;
+ API_SIGNED d_mldt;
+ API_SIGNED d_maccthresh;
+ API_SIGNED d_gu;
+ API_SIGNED d_go;
+ API_SIGNED d_attmax;
+ API_SIGNED d_sm;
+ API_SIGNED d_b;
+
+ #if (VOC == FR_HR) || (VOC == FR_HR_EFR)
+ //...................................TCH Half Speech.
+ API_SIGNED d_ldT_hr;
+ API_SIGNED d_maccthresh_hr;
+ API_SIGNED d_maccthresh1_hr;
+ API_SIGNED d_gu_hr;
+ API_SIGNED d_go_hr;
+ API_SIGNED d_b_hr;
+ API_SIGNED d_sm_hr;
+ API_SIGNED d_attmax_hr;
+ #endif
+
+ #if (VOC == FR_EFR) || (VOC == FR_HR_EFR)
+ //...................................TCH Enhanced FR Speech.
+ API_SIGNED c_mldt_efr;
+ API_SIGNED c_maccthresh_efr;
+ API_SIGNED c_maccthresh1_efr;
+ API_SIGNED c_gu_efr;
+ API_SIGNED c_go_efr;
+ API_SIGNED c_b_efr;
+ API_SIGNED c_sm_efr;
+ API_SIGNED c_attmax_efr;
+ #endif
+
+ //...................................TCH Full Speech.
+ API_SIGNED d_sd_min_thr_tchfs;
+ API_SIGNED d_ma_min_thr_tchfs;
+ API_SIGNED d_md_max_thr_tchfs;
+ API_SIGNED d_md1_max_thr_tchfs;
+
+ #if (VOC == FR) || (VOC == FR_HR) || (VOC == FR_HR_EFR)
+ //...................................TCH Half Speech.
+ API_SIGNED d_sd_min_thr_tchhs;
+ API_SIGNED d_ma_min_thr_tchhs;
+ API_SIGNED d_sd_av_thr_tchhs;
+ API_SIGNED d_md_max_thr_tchhs;
+ API_SIGNED d_md1_max_thr_tchhs;
+ #endif
+
+ #if (VOC == FR_EFR) || (VOC == FR_HR_EFR)
+ //...................................TCH Enhanced FR Speech.
+ API_SIGNED d_sd_min_thr_tchefs; //(24L *C_POND_RED)
+ API_SIGNED d_ma_min_thr_tchefs; //(1200L *C_POND_RED)
+ API_SIGNED d_md_max_thr_tchefs; //(2000L *C_POND_RED)
+ API_SIGNED d_md1_max_thr_tchefs; //(160L *C_POND_RED)
+ API_SIGNED d_hole1;
+ #endif
+
+ API_SIGNED d_wed_fil_ini;
+ API_SIGNED d_wed_fil_tc;
+ API_SIGNED d_x_min;
+ API_SIGNED d_x_max;
+ API_SIGNED d_slope;
+ API_SIGNED d_y_min;
+ API_SIGNED d_y_max;
+ API_SIGNED d_wed_diff_threshold;
+ API_SIGNED d_mabfi_min_thr_tchhs;
+ API_SIGNED d_facch_thr;
+ API_SIGNED d_dsp_test;
+
+
+ #if (DATA14_4 == 0 ) || (VOC == FR_HR_EFR)
+ API_SIGNED d_patch_addr1;
+ API_SIGNED d_patch_data1;
+ API_SIGNED d_patch_addr2;
+ API_SIGNED d_patch_data2;
+ API_SIGNED d_patch_addr3;
+ API_SIGNED d_patch_data3;
+ API_SIGNED d_patch_addr4;
+ API_SIGNED d_patch_data4;
+ #endif
+
+ //...................................
+ API_SIGNED d_version_number; // DSP patch version
+ API_SIGNED d_ti_version; // customer number. No more used since 1.5
+
+ API_SIGNED d_dsp_page;
+
+ #if IDS
+ API_SIGNED d_max_ovsp_ul;
+ API_SIGNED d_sync_thres;
+ API_SIGNED d_idle_thres;
+ API_SIGNED d_m1_thres;
+ API_SIGNED d_max_ovsp_dl;
+ #endif
+
+
+}
+T_PARAM_MCU_DSP;
+#endif
+
+#if (DSP_DEBUG_TRACE_ENABLE == 1)
+typedef struct
+{
+ API d_debug_ptr_begin;
+ API d_debug_ptr_end;
+}
+T_DB2_DSP_TO_MCU;
+#endif
+
+/* DSP error as per ndb->d_error_status */
+enum dsp_error {
+ DSP_ERR_RHEA = 0x0001,
+ DSP_ERR_IQ_SAMPLES = 0x0004,
+ DSP_ERR_DMA_PROG = 0x0008,
+ DSP_ERR_DMA_TASK = 0x0010,
+ DSP_ERR_DMA_PEND = 0x0020,
+ DSP_ERR_VM = 0x0080,
+ DSP_ERR_DMA_UL_TASK = 0x0100,
+ DSP_ERR_DMA_UL_PROG = 0x0200,
+ DSP_ERR_DMA_UL_PEND = 0x0400,
+ DSP_ERR_STACK_OV = 0x0800,
+};
+
+/* How an ABB register + value is expressed in the API RAM */
+#define ABB_VAL(reg, val) ( (((reg) & 0x1F) << 1) | (((val) & 0x3FF) << 6) )
+
+/* How an ABB register + value | TRUE is expressed in the API RAM */
+#define ABB_VAL_T(reg, val) (ABB_VAL(reg, val) | 1)
+
+#endif /* _CAL_DSP_API_H */
diff --git a/src/target/firmware/include/calypso/du.h b/src/target/firmware/include/calypso/du.h
new file mode 100644
index 00000000..f2eae091
--- /dev/null
+++ b/src/target/firmware/include/calypso/du.h
@@ -0,0 +1,32 @@
+/* Calypso DU (Debug Unit) Driver */
+
+/* (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _CALYPSO_DU_H
+#define _CALYPSO_DU_H
+
+#include <calypso/clock.h>
+
+void calypso_du_init();
+void calypso_du_stop();
+void calypsu_du_dump();
+
+#endif /* _CALYPSO_DU_H */
diff --git a/src/target/firmware/include/calypso/irq.h b/src/target/firmware/include/calypso/irq.h
new file mode 100644
index 00000000..5ea59797
--- /dev/null
+++ b/src/target/firmware/include/calypso/irq.h
@@ -0,0 +1,49 @@
+#ifndef _CALYPSO_IRQ_H
+#define _CALYPSO_IRQ_H
+
+enum irq_nr {
+ IRQ_WATCHDOG = 0,
+ IRQ_TIMER1 = 1,
+ IRQ_TIMER2 = 2,
+ IRQ_TSP_RX = 3,
+ IRQ_TPU_FRAME = 4,
+ IRQ_TPU_PAGE = 5,
+ IRQ_SIMCARD = 6,
+ IRQ_UART_MODEM = 7,
+ IRQ_KEYPAD_GPIO = 8,
+ IRQ_RTC_TIMER = 9,
+ IRQ_RTC_ALARM_I2C = 10,
+ IRQ_ULPD_GAUGING = 11,
+ IRQ_EXTERNAL = 12,
+ IRQ_SPI = 13,
+ IRQ_DMA = 14,
+ IRQ_API = 15,
+ IRQ_SIM_DETECT = 16,
+ IRQ_EXTERNAL_FIQ = 17,
+ IRQ_UART_IRDA = 18,
+ IRQ_ULPD_GSM_TIMER = 19,
+ IRQ_GEA = 20,
+ _NR_IRQ
+};
+
+typedef void irq_handler(enum irq_nr nr);
+
+/* initialize IRQ driver and enable interrupts */
+void irq_init(void);
+
+/* enable a certain interrupt */
+void irq_enable(enum irq_nr nr);
+
+/* disable a certain interrupt */
+void irq_disable(enum irq_nr nr);
+
+/* configure a certain interrupt */
+void irq_config(enum irq_nr nr, int fiq, int edge, int8_t prio);
+
+/* register an interrupt handler */
+void irq_register_handler(enum irq_nr nr, irq_handler *handler);
+
+/* Install the exception handlers to where the ROM loader jumps */
+void calypso_exceptions_install(void);
+
+#endif /* _CALYPSO_IRQ_H */
diff --git a/src/target/firmware/include/calypso/l1_environment.h b/src/target/firmware/include/calypso/l1_environment.h
new file mode 100644
index 00000000..d4d442cc
--- /dev/null
+++ b/src/target/firmware/include/calypso/l1_environment.h
@@ -0,0 +1,385 @@
+#include <stdint.h>
+
+typedef unsigned short API;
+typedef signed short API_SIGNED;
+
+#define FAR
+
+#define CHIPSET 12
+#define DSP 36
+#define ANLG_FAM 2 /* Iota */
+
+/* MFTAB */
+#define L1_MAX_FCT 5 /* Max number of fctions in a frame */
+#define MFTAB_SIZE 20
+
+#define NBMAX_CARRIER 174+374 /* Number of carriers (GSM-Ext + DCS */
+
+#define DPAGC_FIFO_LEN 4
+
+#define SIZE_HIST 10
+
+#if !L1_GPRS
+# define NBR_DL_L1S_TASKS 32
+#else
+# define NBR_DL_L1S_TASKS 45
+#endif
+
+#define NBR_L1A_PROCESSES 46
+
+#define W_A_DSP_IDLE3 1
+
+
+
+// Identifier for all DSP tasks.
+// ...RX & TX tasks identifiers.
+#define NO_DSP_TASK 0 // No task.
+#define NP_DSP_TASK 21 // Normal Paging reading task.
+#define EP_DSP_TASK 22 // Extended Paging reading task.
+#define NBS_DSP_TASK 19 // Normal BCCH serving reading task.
+#define EBS_DSP_TASK 20 // Extended BCCH serving reading task.
+#define NBN_DSP_TASK 17 // Normal BCCH neighbour reading task.
+#define EBN_DSP_TASK 18 // Extended BCCH neighbour reading task.
+#define ALLC_DSP_TASK 24 // CCCH reading task while performing FULL BCCH/CCCH reading task.
+#define CB_DSP_TASK 25 // CBCH reading task.
+#define DDL_DSP_TASK 26 // SDCCH/D (data) reading task.
+#define ADL_DSP_TASK 27 // SDCCH/A (SACCH) reading task.
+#define DUL_DSP_TASK 12 // SDCCH/D (data) transmit task.
+#define AUL_DSP_TASK 11 // SDCCH/A (SACCH) transmit task.
+#define RACH_DSP_TASK 10 // RACH transmit task.
+#define TCHT_DSP_TASK 13 // TCH Traffic data DSP task id (RX or TX)
+#define TCHA_DSP_TASK 14 // TCH SACCH data DSP task id (RX or TX)
+#define TCHD_DSP_TASK 28 // TCH Traffic data DSP task id (RX or TX)
+
+#define TCH_DTX_UL 15 // Replace UL task in DSP->MCU com. to say "burst not transmitted".
+
+#if (L1_GPRS)
+ // Identifier for DSP tasks Packet dedicated.
+ // ...RX & TX tasks identifiers.
+ //------------------------------------------------------------------------
+ // WARNING ... Need to aligned following macro with MCU/DSP GPRS Interface
+ //------------------------------------------------------------------------
+ #define PNP_DSP_TASK 30
+ #define PEP_DSP_TASK 31
+ #define PALLC_DSP_TASK 32
+ #define PBS_DSP_TASK 33
+
+ #define PTCCH_DSP_TASK 33
+
+#endif
+
+// Identifier for measurement, FB / SB search tasks.
+// Values 1,2,3 reserved for "number of measurements".
+#define FB_DSP_TASK 5 // Freq. Burst reading task in Idle mode.
+#define SB_DSP_TASK 6 // Sync. Burst reading task in Idle mode.
+#define TCH_FB_DSP_TASK 8 // Freq. Burst reading task in Dedicated mode.
+#define TCH_SB_DSP_TASK 9 // Sync. Burst reading task in Dedicated mode.
+#define IDLE1 1
+
+// Debug tasks
+#define CHECKSUM_DSP_TASK 33
+#define TST_NDB 35 // Checksum DSP->MCU
+#define TST_DB 36 // DB communication check
+#define INIT_VEGA 37
+#define DSP_LOOP_C 38
+
+// Identifier for measurement, FB / SB search tasks.
+// Values 1,2,3 reserved for "number of measurements".
+#define TCH_LOOP_A 31
+#define TCH_LOOP_B 32
+
+// bits in d_gsm_bgd_mgt - background task management
+#define B_DSPBGD_RECO 1 // start of reco in dsp background
+#define B_DSPBGD_UPD 2 // start of alignement update in dsp background
+#define B_DSPBGD_STOP_RECO 256 // stop of reco in dsp background
+#define B_DSPBGD_STOP_UPD 512 // stop of alignement update in dsp background
+
+// bit in d_pll_config
+#define B_32KHZ_CALIB (1 << 14) // force DSP in Idle1 during 32 khz calibration
+// ****************************************************************
+// NDB AREA (PARAM) MCU<->DSP COMMUNICATION DEFINITIONS
+// ****************************************************************
+// bits in d_tch_mode
+#define B_EOTD (1 << 0) // EOTD mode
+#define B_PLAY_UL (1 << 3) // Play UL
+#define B_DCO_ON (1 << 4) // DCO ON/OFF
+#define B_AUDIO_ASYNC (1 << 1) // WCP reserved
+
+// ****************************************************************
+// PARAMETER AREA (PARAM) MCU<->DSP COMMUNICATION DEFINITIONS
+// ****************************************************************
+#define C_POND_RED 1L
+// below values are defined in the file l1_time.h
+//#define D_NSUBB_IDLE 296L
+//#define D_NSUBB_DEDIC 30L
+#define D_FB_THR_DET_IACQ 0x3333L
+#define D_FB_THR_DET_TRACK 0x28f6L
+#define D_DC_OFF_THRES 0x7fffL
+#define D_DUMMY_THRES 17408L
+#define D_DEM_POND_GEWL 26624L
+#define D_DEM_POND_RED 20152L
+#define D_HOLE 0L
+#define D_TRANSFER_RATE 0x6666L
+
+// Full Rate vocoder definitions.
+#define D_MACCTHRESH1 7872L
+#define D_MLDT -4L
+#define D_MACCTHRESH 7872L
+#define D_GU 5772L
+#define D_GO 7872L
+#define D_ATTMAX 53L
+#define D_SM -892L
+#define D_B 208L
+#define D_SD_MIN_THR_TCHFS 15L //(24L *C_POND_RED)
+#define D_MA_MIN_THR_TCHFS 738L //(1200L *C_POND_RED)
+#define D_MD_MAX_THR_TCHFS 1700L //(2000L *C_POND_RED)
+#define D_MD1_MAX_THR_TCHFS 99L //(160L *C_POND_RED)
+
+#if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ // Frequency burst definitions
+ #define D_FB_MARGIN_BEG 24
+ #define D_FB_MARGIN_END 22
+
+ // V42bis definitions
+ #define D_V42B_SWITCH_HYST 16L
+ #define D_V42B_SWITCH_MIN 64L
+ #define D_V42B_SWITCH_MAX 250L
+ #define D_V42B_RESET_DELAY 10L
+
+ // Latencies definitions
+ #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ // C.f. BUG1404
+ #define D_LAT_MCU_BRIDGE 0x000FL
+ #else
+ #define D_LAT_MCU_BRIDGE 0x0009L
+ #endif
+
+ #define D_LAT_MCU_HOM2SAM 0x000CL
+
+ #define D_LAT_MCU_BEF_FAST_ACCESS 0x0005L
+ #define D_LAT_DSP_AFTER_SAM 0x0004L
+
+ // Background Task in GSM mode: Initialization.
+ #define D_GSM_BGD_MGT 0L
+
+#if (CHIPSET == 4)
+ #define D_MISC_CONFIG 0L
+#elif (CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12)
+ #define D_MISC_CONFIG 1L
+#else
+ #define D_MISC_CONFIG 0L
+#endif
+
+#endif
+
+// Hall Rate vocoder and ched definitions.
+
+#define D_SD_MIN_THR_TCHHS 37L
+#define D_MA_MIN_THR_TCHHS 344L
+#define D_MD_MAX_THR_TCHHS 2175L
+#define D_MD1_MAX_THR_TCHHS 138L
+#define D_SD_AV_THR_TCHHS 1845L
+#define D_WED_FIL_TC 0x7c00L
+#define D_WED_FIL_INI 4650L
+#define D_X_MIN 15L
+#define D_X_MAX 23L
+#define D_Y_MIN 703L
+#define D_Y_MAX 2460L
+#define D_SLOPE 135L
+#define D_WED_DIFF_THRESHOLD 406L
+#define D_MABFI_MIN_THR_TCHHS 5320L
+#define D_LDT_HR -5
+#define D_MACCTRESH_HR 6500
+#define D_MACCTRESH1_HR 6500
+#define D_GU_HR 2620
+#define D_GO_HR 3700
+#define D_B_HR 182
+#define D_SM_HR -1608
+#define D_ATTMAX_HR 53
+
+// Enhanced Full Rate vocoder and ched definitions.
+
+#define C_MLDT_EFR -4
+#define C_MACCTHRESH_EFR 8000
+#define C_MACCTHRESH1_EFR 8000
+#define C_GU_EFR 4522
+#define C_GO_EFR 6500
+#define C_B_EFR 174
+#define C_SM_EFR -878
+#define C_ATTMAX_EFR 53
+#define D_SD_MIN_THR_TCHEFS 15L //(24L *C_POND_RED)
+#define D_MA_MIN_THR_TCHEFS 738L //(1200L *C_POND_RED)
+#define D_MD_MAX_THR_TCHEFS 1230L //(2000L *C_POND_RED)
+#define D_MD1_MAX_THR_TCHEFS 99L //(160L *C_POND_RED)
+
+
+// Integrated Data Services definitions.
+#define D_MAX_OVSPD_UL 8
+// Detect frames containing 90% of 1s as synchro frames
+#define D_SYNC_THRES 0x3f50
+// IDLE frames are only frames with 100 % of 1s
+#define D_IDLE_THRES 0x4000
+#define D_M1_THRES 5
+#define D_MAX_OVSP_DL 8
+
+// d_ra_act: bit field definition
+#define B_F48BLK 5
+
+// Mask for b_itc information (d_ra_conf)
+#define CE_MASK 0x04
+
+#define D_FACCH_THR 0
+#define D_DSP_TEST 0
+#define D_VERSION_NUMBER 0
+#define D_TI_VERSION 0
+
+
+/*------------------------------------------------------------------------------*/
+/* */
+/* DEFINITIONS FOR DSP <-> MCU COMMUNICATION. */
+/* ++++++++++++++++++++++++++++++++++++++++++ */
+/* */
+/*------------------------------------------------------------------------------*/
+// COMMUNICATION Interrupt definition
+//------------------------------------
+#define ALL_16BIT 0xffffL
+#define B_GSM_PAGE (1 << 0)
+#define B_GSM_TASK (1 << 1)
+#define B_MISC_PAGE (1 << 2)
+#define B_MISC_TASK (1 << 3)
+
+#define B_GSM_PAGE_MASK (ALL_16BIT ^ B_GSM_PAGE)
+#define B_GSM_TASK_MASK (ALL_16BIT ^ B_GSM_TASK)
+#define B_MISC_PAGE_MASK (ALL_16BIT ^ B_MISC_PAGE)
+#define B_MISC_TASK_MASK (ALL_16BIT ^ B_MISC_TASK)
+
+// Common definition
+//----------------------------------
+// Index to *_DEMOD* arrays.
+#define D_TOA 0 // Time Of Arrival.
+#define D_PM 1 // Power Measurement.
+#define D_ANGLE 2 // Angle (AFC correction)
+#define D_SNR 3 // Signal / Noise Ratio.
+
+// Bit name/position definitions.
+#define B_FIRE0 5 // Fire result bit 0. (00 -> NO ERROR) (01 -> ERROR CORRECTED)
+#define B_FIRE1 6 // Fire result bit 1. (10 -> ERROR) (11 -> unused)
+#define B_SCH_CRC 8 // CRC result for SB decoding. (1 for ERROR).
+#define B_BLUD 15 // Uplink,Downlink data block Present. (1 for PRESENT).
+#define B_AF 14 // Activity bit: 1 if data block is valid.
+#define B_BFI 2 // Bad Frame Indicator
+#define B_UFI 0 // UNRELIABLE FRAME Indicator
+#define B_ECRC 9 // Enhanced full rate CRC bit
+#define B_EMPTY_BLOCK 10 // for voice memo purpose, this bit is used to determine
+
+#if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1)
+ #define FACCH_GOOD 10
+ #define FACCH_BAD 11
+#endif
+
+#if (AMR == 1)
+ // Place of the RX type in the AMR block header
+ #define RX_TYPE_SHIFT 3
+ #define RX_TYPE_MASK 0x0038
+
+ // Place of the vocoder type in the AMR block header
+ #define VOCODER_TYPE_SHIFT 0
+ #define VOCODER_TYPE_MASK 0x0007
+
+ // List of the possible RX types in a_dd block
+ #define SPEECH_GOOD 0
+ #define SPEECH_DEGRADED 1
+ #define ONSET 2
+ #define SPEECH_BAD 3
+ #define SID_FIRST 4
+ #define SID_UPDATE 5
+ #define SID_BAD 6
+ #define AMR_NO_DATA 7
+ #define AMR_INHIBIT 8
+
+ // List of possible RX types in RATSCCH block
+ #define C_RATSCCH_GOOD 5
+
+ // List of the possible AMR channel rate
+ #define AMR_CHANNEL_4_75 0
+ #define AMR_CHANNEL_5_15 1
+ #define AMR_CHANNEL_5_9 2
+ #define AMR_CHANNEL_6_7 3
+ #define AMR_CHANNEL_7_4 4
+ #define AMR_CHANNEL_7_95 5
+ #define AMR_CHANNEL_10_2 6
+ #define AMR_CHANNEL_12_2 7
+
+ // Types of RATSCCH blocks
+ #define C_RATSCCH_UNKNOWN 0
+ #define C_RATSCCH_CMI_PHASE_REQ 1
+ #define C_RATSCCH_AMR_CONFIG_REQ_MAIN 2
+ #define C_RATSCCH_AMR_CONFIG_REQ_ALT 3
+ #define C_RATSCCH_AMR_CONFIG_REQ_ALT_IGNORE 4 // Alternative AMR_CONFIG_REQ with updates coming in the next THRES_REQ block
+ #define C_RATSCCH_THRES_REQ 5
+
+ // These flags define a bitmap that indicates which AMR parameters are being modified by a RATSCCH
+ #define C_AMR_CHANGE_CMIP 0
+ #define C_AMR_CHANGE_ACS 1
+ #define C_AMR_CHANGE_ICM 2
+ #define C_AMR_CHANGE_THR1 3
+ #define C_AMR_CHANGE_THR2 4
+ #define C_AMR_CHANGE_THR3 5
+ #define C_AMR_CHANGE_HYST1 6
+ #define C_AMR_CHANGE_HYST2 7
+ #define C_AMR_CHANGE_HYST3 8
+
+ // CMIP default value
+ #define C_AMR_CMIP_DEFAULT 1 // According to ETSI specification 05.09, cmip is always 1 by default (new channel, handover...)
+
+#endif
+// "d_ctrl_tch" bits positions for TCH configuration.
+#define B_CHAN_MODE 0
+#define B_CHAN_TYPE 4
+#define B_RESET_SACCH 6
+#define B_VOCODER_ON 7
+#define B_SYNC_TCH_UL 8
+#if (AMR == 1)
+ #define B_SYNC_AMR 9
+#else
+#define B_SYNC_TCH_DL 9
+#endif
+#define B_STOP_TCH_UL 10
+#define B_STOP_TCH_DL 11
+#define B_TCH_LOOP 12
+#define B_SUBCHANNEL 15
+
+// "d_ctrl_abb" bits positions for conditionnal loading of abb registers.
+#define B_RAMP 0
+#if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
+ #define B_BULRAMPDEL 3 // Note: this name is changed
+ #define B_BULRAMPDEL2 2 // Note: this name is changed
+ #define B_BULRAMPDEL_BIS 9
+ #define B_BULRAMPDEL2_BIS 10
+#endif
+#define B_AFC 4
+
+// "d_ctrl_system" bits positions.
+#define B_TSQ 0
+#define B_BCCH_FREQ_IND 3
+#define B_TASK_ABORT 15 // Abort RF tasks for DSP.
+
+/* Channel type definitions for DEDICATED mode */
+#define INVALID_CHANNEL 0
+#define TCH_F 1
+#define TCH_H 2
+#define SDCCH_4 3
+#define SDCCH_8 4
+
+/* Channel mode definitions for DEDICATED mode */
+#define SIG_ONLY_MODE 0 // signalling only
+#define TCH_FS_MODE 1 // speech full rate
+#define TCH_HS_MODE 2 // speech half rate
+#define TCH_96_MODE 3 // data 9,6 kb/s
+#define TCH_48F_MODE 4 // data 4,8 kb/s full rate
+#define TCH_48H_MODE 5 // data 4,8 kb/s half rate
+#define TCH_24F_MODE 6 // data 2,4 kb/s full rate
+#define TCH_24H_MODE 7 // data 2,4 kb/s half rate
+#define TCH_EFR_MODE 8 // enhanced full rate
+#define TCH_144_MODE 9 // data 14,4 kb/s half rate
+
diff --git a/src/target/firmware/include/calypso/misc.h b/src/target/firmware/include/calypso/misc.h
new file mode 100644
index 00000000..4e480938
--- /dev/null
+++ b/src/target/firmware/include/calypso/misc.h
@@ -0,0 +1,8 @@
+#ifndef _CAL_MISC_H
+#define _CAL_MISC_H
+
+void memdump_range(unsigned int *ptr, unsigned int len);
+void dump_mem(void);
+void dump_dev_id(void);
+
+#endif /* _CAL_MISC_H */
diff --git a/src/target/firmware/include/calypso/rtc.h b/src/target/firmware/include/calypso/rtc.h
new file mode 100644
index 00000000..17528d00
--- /dev/null
+++ b/src/target/firmware/include/calypso/rtc.h
@@ -0,0 +1,6 @@
+#ifndef _CALYPSO_RTC_H
+#define _CALYPSO_RTC_H
+
+void rtc_init(void);
+
+#endif /* _CALYPSO_RTC_H */
diff --git a/src/target/firmware/include/calypso/sim.h b/src/target/firmware/include/calypso/sim.h
new file mode 100755
index 00000000..5e33bdbd
--- /dev/null
+++ b/src/target/firmware/include/calypso/sim.h
@@ -0,0 +1,179 @@
+/* Driver for Simcard Controller inside TI Calypso/Iota */
+
+/* (C) 2010 by Philipp Fabian Benedikt Maier <philipp-maier@runningserver.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _CALYPSO_SIM_H
+#define _CALYPSO_SIM_H
+
+/* == REGISTERS IN THE IOTA BASEBAND == */
+
+/* SimCard Control Register */
+#define VRPCSIM_SIMLEN (1 << 3) /* Enable level shifter */
+#define VRPCSIM_SIMRSU (1 << 2) /* voltage regulator output status */
+#define VRPCSIM_RSIMEN (1 << 1) /* Voltage regulator enable */
+#define VRPCSIM_SIMSEL 1 /* Select the VRSIM output voltage 1=2.9V, 0=1.8V */
+
+
+
+/* == REGISTERS IN THE CALYPSO CPU == */
+
+/* Reg_sim_cmd register (R/W) - FFFE:0000 */
+#define REG_SIM_CMD 0xFFFE0000 /* register address */
+#define REG_SIM_CMD_CMDCARDRST 1 /* SIM card reset sequence */
+#define REG_SIM_CMD_CMDIFRST (1 << 1) /* SIM interface software reset */
+#define REG_SIM_CMD_CMDSTOP (1 << 2) /* SIM card stop procedure */
+#define REG_SIM_CMD_CMDSTART (1 << 3) /* SIM card start procedure */
+#define REG_SIM_CMD_MODULE_CLK_EN (1 << 4) /* Clock of the module */
+
+/* Reg_sim_stat register (R) - FFFE:0002 */
+#define REG_SIM_STAT 0xFFFE0002 /* register address */
+#define REG_SIM_STAT_STATNOCARD 1 /* card presence, 0 = no card, 1 = card detected */
+#define REG_SIM_STAT_STATTXPAR (1 << 1) /* parity check for transmit byte, 0 = parity error, 1 = parity OK */
+#define REG_SIM_STAT_STATFIFOFULL (1 << 2) /* FIFO content, 1 = FIFO full */
+#define REG_SIM_STAT_STATFIFOEMPTY (1 << 3) /* FIFO content, 1 = FIFO empty */
+
+/* Reg_sim_conf1 register (R/W) - FFFE:0004 */
+#define REG_SIM_CONF1 0xFFFE0004 /* register address */
+#define REG_SIM_CONF1_CONFCHKPAR 1 /* enable parity check on reception */
+#define REG_SIM_CONF1_CONFCODCONV (1 << 1) /* coding convention: (TS character) */
+#define REG_SIM_CONF1_CONFTXRX (1 << 2) /* SIO line direction */
+#define REG_SIM_CONF1_CONFSCLKEN (1 << 3) /* SIM clock */
+#define REG_SIM_CONF1_reserved (1 << 4) /* ETU period */
+#define REG_SIM_CONF1_CONFSCLKDIV (1 << 5) /* SIM clock frequency */
+#define REG_SIM_CONF1_CONFSCLKLEV (1 << 6) /* SIM clock idle level */
+#define REG_SIM_CONF1_CONFETUPERIOD (1 << 7) /* ETU period */
+#define REG_SIM_CONF1_CONFBYPASS (1 << 8) /* bypass hardware timers and start and stop sequences */
+#define REG_SIM_CONF1_CONFSVCCLEV (1 << 9) /* logic level on SVCC (used if CONFBYPASS = 1) */
+#define REG_SIM_CONF1_CONFSRSTLEV (1 << 10) /* logic level on SRST (used if CONFBYPASS = 1) */
+#define REG_SIM_CONF1_CONFTRIG 11 /* FIFO trigger level */
+#define REG_SIM_CONF1_CONFTRIG_0 (1 << 11)
+#define REG_SIM_CONF1_CONFTRIG_1 (1 << 12)
+#define REG_SIM_CONF1_CONFTRIG_2 (1 << 13)
+#define REG_SIM_CONF1_CONFTRIG_3 (1 << 14)
+#define REG_SIM_CONF1_CONFTRIG_MASK 0xF
+#define REG_SIM_CONF1_CONFSIOLOW (1 << 15) /* SIO - 0 = no effect, 1 = force low */
+
+/* Reg_sim_conf2 register (R/W) - FFFE:0006 */
+#define REG_SIM_CONF2 0xFFFE0006 /* register address */
+#define REG_SIM_CONF2_CONFTFSIM 0 /* time delay for filtering of SIM_CD */
+#define REG_SIM_CONF2_CONFTFSIM_0 1 /* time-unit = 1024 * TCK13M (card extraction) */
+#define REG_SIM_CONF2_CONFTFSIM_1 (1 << 1) /* or */
+#define REG_SIM_CONF2_CONFTFSIM_2 (1 << 2) /* time-unit = 8192 * TCK13M (card insertion) */
+#define REG_SIM_CONF2_CONFTFSIM_3 (1 << 3)
+#define REG_SIM_CONF2_CONFTFSIM_MASK 0xF
+#define REG_SIM_CONF2_CONFTDSIM 4 /* time delay for contact activation/deactivation */
+#define REG_SIM_CONF2_CONFTDSIM_0 (1 << 4) /* time unit = 8 * TCKETU */
+#define REG_SIM_CONF2_CONFTDSIM_1 (1 << 5)
+#define REG_SIM_CONF2_CONFTDSIM_2 (1 << 6)
+#define REG_SIM_CONF2_CONFTDSIM_3 (1 << 7)
+#define REG_SIM_CONF2_CONFTDSIM_MASK 0xF
+#define REG_SIM_CONF2_CONFWAITI 8 /* CONFWAITI overflow wait time between two received */
+#define REG_SIM_CONF2_CONFWAITI_0 (1 << 8) /* character time unit = 960 *D * TCKETU */
+#define REG_SIM_CONF2_CONFWAITI_1 (1 << 9) /* with D parameter = 1 or 8 (TA1 character) */
+#define REG_SIM_CONF2_CONFWAITI_2 (1 << 10)
+#define REG_SIM_CONF2_CONFWAITI_3 (1 << 11)
+#define REG_SIM_CONF2_CONFWAITI_4 (1 << 12)
+#define REG_SIM_CONF2_CONFWAITI_5 (1 << 13)
+#define REG_SIM_CONF2_CONFWAITI_6 (1 << 14)
+#define REG_SIM_CONF2_CONFWAITI_7 (1 << 15)
+#define REG_SIM_CONF2_CONFWAITI_MASK 0xFF
+
+/* Reg_sim_it register (R) - FFFE:0008 */
+#define REG_SIM_IT 0xFFFE0008 /* register address */
+#define REG_SIM_IT_SIM_NATR 1 /* 0 = on read access to REG_SIM_IT, 1 = no answer to reset */
+#define REG_SIM_IT_SIM_WT (1 << 1) /* 0 = on read access to REG_SIM_IT, 1 = character underflow */
+#define REG_SIM_IT_SIM_OV (1 << 2) /* 0 = on read access to REG_SIM_IT, 1 = receive overflow */
+#define REG_SIM_IT_SIM_TX (1 << 3) /* 0 = on write access to REG_SIM_DTX or */
+ /* on switching from transmit to receive, mode (CONFTXRX bit) */
+ /* 1 = waiting for character to transmit */
+#define REG_SIM_IT_SIM_RX (1 << 4) /* 0 = on read access to REG_SIM_DRX */
+ /* 1 = waiting characters to be read */
+
+/* Reg_sim_drx register (R) - FFFE:000A */
+#define REG_SIM_DRX 0xFFFE000A /* register address */
+#define REG_SIM_DRX_SIM_DRX 0 /* next data byte in FIFO available for reading */
+#define REG_SIM_DRX_SIM_DRX_0 1
+#define REG_SIM_DRX_SIM_DRX_1 (1 << 1)
+#define REG_SIM_DRX_SIM_DRX_2 (1 << 2)
+#define REG_SIM_DRX_SIM_DRX_3 (1 << 3)
+#define REG_SIM_DRX_SIM_DRX_4 (1 << 4)
+#define REG_SIM_DRX_SIM_DRX_5 (1 << 5)
+#define REG_SIM_DRX_SIM_DRX_6 (1 << 6)
+#define REG_SIM_DRX_SIM_DRX_7 (1 << 7)
+#define REG_SIM_DRX_SIM_DRX_MASK 0xFF
+#define REG_SIM_DRX_STATRXPAR (1 << 8) /* parity-check for received byte */
+
+/* Reg_sim_dtx register (R/W) - FFFE:000C */
+#define REG_SIM_DTX 0xFFFE000C /* register address */
+#define REG_SIM_DTX_SIM_DTX_0 /* next data byte to be transmitted */
+#define REG_SIM_DTX_SIM_DTX_1
+#define REG_SIM_DTX_SIM_DTX_2
+#define REG_SIM_DTX_SIM_DTX_3
+#define REG_SIM_DTX_SIM_DTX_4
+#define REG_SIM_DTX_SIM_DTX_5
+#define REG_SIM_DTX_SIM_DTX_6
+#define REG_SIM_DTX_SIM_DTX_7
+
+/* Reg_sim_maskit register (R/W) - FFFE:000E */
+#define REG_SIM_MASKIT 0xFFFE000E /* register address */
+#define REG_SIM_MASKIT_MASK_SIM_NATR 1 /* No-answer-to-reset interrupt */
+#define REG_SIM_MASKIT_MASK_SIM_WT (1 << 1) /* Character wait-time overflow interrupt */
+#define REG_SIM_MASKIT_MASK_SIM_OV (1 << 2) /* Receive overflow interrupt */
+#define REG_SIM_MASKIT_MASK_SIM_TX (1 << 3) /* Waiting character to transmit interrupt */
+#define REG_SIM_MASKIT_MASK_SIM_RX (1 << 4) /* Waiting characters to be read interrupt */
+#define REG_SIM_MASKIT_MASK_SIM_CD (1 << 5) /* SIM card insertion/extraction interrupt */
+
+/* Reg_sim_it_cd register (R) - FFFE:0010 */
+#define REG_SIM_IT_CD 0xFFFE0010 /* register address */
+#define REG_SIM_IT_CD_IT_CD 1 /* 0 = on read access to REG_SIM_IT_CD, */
+ /* 1 = SIM card insertion/extraction */
+
+
+#define SIM_OPERATION_DELAY 100 /* Time between operations like reset, vcc apply ect... */
+
+
+void calypso_sim_regdump(void); /* Display Register dump */
+
+int calypso_sim_powerup(uint8_t *atr); /* Apply power to the simcard (see note 1) */
+int calypso_sim_reset(uint8_t *atr); /* reset the simcard (see note 1) */
+
+
+void calypso_sim_powerdown(void); /* Powerdown simcard */
+
+/* APDU transmission modes */
+#define SIM_APDU_PUT 0 /* Transmit a data body to the card */
+#define SIM_APDU_GET 1 /* Fetch data from the card eg. GET RESOPNSE */
+
+
+void calypso_sim_init(void); /* Initialize simcard interface */
+
+/* handling sim events */
+void sim_handler(void);
+
+/* simm command from layer 23 */
+void sim_apdu(uint16_t len, uint8_t *data);
+
+
+/* Known Bugs:
+ 1.) After powering down the simcard communication stops working
+*/
+
+#endif /* _CALYPSO_SIM_H */
diff --git a/src/target/firmware/include/calypso/timer.h b/src/target/firmware/include/calypso/timer.h
new file mode 100644
index 00000000..694e4ebc
--- /dev/null
+++ b/src/target/firmware/include/calypso/timer.h
@@ -0,0 +1,25 @@
+#ifndef _CAL_TIMER_H
+#define _CAL_TIMER_H
+
+/* Enable or Disable a timer */
+void hwtimer_enable(int num, int on);
+
+/* Configure pre-scaler and if timer is auto-reload */
+void hwtimer_config(int num, uint8_t pre_scale, int auto_reload);
+
+/* Load a timer with the given value */
+void hwtimer_load(int num, uint16_t val);
+
+/* Read the current timer value */
+uint16_t hwtimer_read(int num);
+
+/* Enable or disable the watchdog */
+void wdog_enable(int on);
+
+/* Reset cpu using watchdog */
+void wdog_reset(void);
+
+/* power up the timers */
+void hwtimer_init(void);
+
+#endif /* _CAL_TIMER_H */
diff --git a/src/target/firmware/include/calypso/tpu.h b/src/target/firmware/include/calypso/tpu.h
new file mode 100644
index 00000000..3b1b6007
--- /dev/null
+++ b/src/target/firmware/include/calypso/tpu.h
@@ -0,0 +1,122 @@
+#ifndef _CALYPSO_TPU_H
+#define _CALYPSO_TPU_H
+
+#define BITS_PER_TDMA 1250
+#define QBITS_PER_TDMA (BITS_PER_TDMA * 4) /* 5000 */
+#define TPU_RANGE QBITS_PER_TDMA
+#define SWITCH_TIME (TPU_RANGE-10)
+
+/* Assert or de-assert TPU reset */
+void tpu_reset(int active);
+/* Enable or Disable a new scenario loaded into the TPU */
+void tpu_enable(int active);
+/* Enable or Disable the clock of the TPU Module */
+void tpu_clk_enable(int active);
+/* Enable Frame Interrupt generation on next frame. DSP will reset it */
+void tpu_dsp_frameirq_enable(void);
+/* Is a Frame interrupt still pending for the DSP ? */
+int tpu_dsp_fameirq_pending(void);
+/* Rewind the TPU, i.e. restart enqueueing instructions at the base addr */
+void tpu_rewind(void);
+/* Enqueue a raw TPU instruction */
+void tpu_enqueue(uint16_t instr);
+/* Initialize TPU and TPU driver */
+void tpu_init(void);
+/* (Busy)Wait until TPU is idle */
+void tpu_wait_idle(void);
+/* Enable FRAME interrupt generation */
+void tpu_frame_irq_en(int mcu, int dsp);
+/* Force the generation of a DSP interrupt */
+void tpu_force_dsp_frame_irq(void);
+
+/* Get the current TPU SYNCHRO register */
+uint16_t tpu_get_synchro(void);
+/* Get the current TPU OFFSET register */
+uint16_t tpu_get_offset(void);
+
+enum tpu_instr {
+ TPU_INSTR_AT = (1 << 13),
+ TPU_INSTR_OFFSET = (2 << 13),
+ TPU_INSTR_SYNCHRO = (3 << 13), /* Loading delta synchro value in TPU synchro register */
+ TPU_INSTR_WAIT = (5 << 13), /* Wait a certain period (in GSM qbits) */
+ TPU_INSTR_SLEEP = (0 << 13), /* Stop the sequencer by disabling TPU ENABLE bit in ctrl reg */
+ /* data processing */
+ TPU_INSTR_MOVE = (4 << 13),
+};
+
+/* Addresses internal to the TPU, only accessible via MOVE */
+enum tpu_reg_int {
+ TPUI_TSP_CTRL1 = 0x00,
+ TPUI_TSP_CTRL2 = 0x01,
+ TPUI_TX_1 = 0x04,
+ TPUI_TX_2 = 0x03,
+ TPUI_TX_3 = 0x02,
+ TPUI_TX_4 = 0x05,
+ TPUI_TSP_ACT_L = 0x06,
+ TPUI_TSP_ACT_U = 0x07,
+ TPUI_TSP_SET1 = 0x09,
+ TPUI_TSP_SET2 = 0x0a,
+ TPUI_TSP_SET3 = 0x0b,
+ TPUI_DSP_INT_PG = 0x10,
+ TPUI_GAUGING_EN = 0x11,
+};
+
+enum tpui_ctrl2_bits {
+ TPUI_CTRL2_RD = (1 << 0),
+ TPUI_CTRL2_WR = (1 << 1),
+};
+
+static inline uint16_t tpu_mod5000(int16_t time)
+{
+ if (time < 0)
+ return time + 5000;
+ if (time >= 5000)
+ return time - 5000;
+ return time;
+}
+
+/* Enqueue a SLEEP operation (stop sequencer by disabling TPU ENABLE bit) */
+static inline void tpu_enq_sleep(void)
+{
+ tpu_enqueue(TPU_INSTR_SLEEP);
+}
+
+/* Enqueue a MOVE operation */
+static inline void tpu_enq_move(uint8_t addr, uint8_t data)
+{
+ tpu_enqueue(TPU_INSTR_MOVE | (data << 5) | (addr & 0x1f));
+}
+
+/* Enqueue an AT operation */
+static inline void tpu_enq_at(int16_t time)
+{
+ tpu_enqueue(TPU_INSTR_AT | tpu_mod5000(time));
+}
+
+/* Enqueue a SYNC operation */
+static inline void tpu_enq_sync(int16_t time)
+{
+ tpu_enqueue(TPU_INSTR_SYNCHRO | time);
+}
+
+/* Enqueue a WAIT operation */
+static inline void tpu_enq_wait(int16_t time)
+{
+ tpu_enqueue(TPU_INSTR_WAIT | time);
+}
+
+/* Enqueue an OFFSET operation */
+static inline void tpu_enq_offset(int16_t time)
+{
+ tpu_enqueue(TPU_INSTR_OFFSET | time);
+}
+
+static inline void tpu_enq_dsp_irq(void)
+{
+ tpu_enq_move(TPUI_DSP_INT_PG, 0x0001);
+}
+
+/* add two numbers, modulo 5000, and ensure the result is positive */
+uint16_t add_mod5000(int16_t a, int16_t b);
+
+#endif /* _CALYPSO_TPU_H */
diff --git a/src/target/firmware/include/calypso/tsp.h b/src/target/firmware/include/calypso/tsp.h
new file mode 100644
index 00000000..d58a562a
--- /dev/null
+++ b/src/target/firmware/include/calypso/tsp.h
@@ -0,0 +1,31 @@
+#ifndef _CALYPSO_TSP_H
+#define _CALYPSO_TSP_H
+
+#define TSPACT(x) (1 << x)
+#define TSPEN(x) (x)
+
+/* initiate a TSP write through the TPU */
+void tsp_write(uint8_t dev_idx, uint8_t bitlen, uint32_t dout);
+
+/* Configure clock edge and chip enable polarity for a device */
+void tsp_setup(uint8_t dev_idx, int clk_rising, int en_positive, int en_edge);
+
+/* Obtain the current tspact state */
+uint16_t tsp_act_state(void);
+
+/* Update the TSPACT state, including enable and disable */
+void tsp_act_update(uint16_t new_act);
+
+/* Enable one or multiple TSPACT signals */
+void tsp_act_enable(uint16_t bitmask);
+
+/* Disable one or multiple TSPACT signals */
+void tsp_act_disable(uint16_t bitmask);
+
+/* Toggle one or multiple TSPACT signals */
+void tsp_act_toggle(uint16_t bitmask);
+
+/* Initialize TSP driver */
+void tsp_init(void);
+
+#endif /* _CALYPSO_TSP_H */
diff --git a/src/target/firmware/include/comm/sercomm.h b/src/target/firmware/include/comm/sercomm.h
new file mode 100644
index 00000000..54256b5a
--- /dev/null
+++ b/src/target/firmware/include/comm/sercomm.h
@@ -0,0 +1,57 @@
+#ifndef _SERCOMM_H
+#define _SERCOMM_H
+
+/* SERCOMM layer on UART1 (modem UART) */
+
+#include <osmocom/core/msgb.h>
+
+#define SERCOMM_UART_NR 1
+
+#define HDLC_FLAG 0x7E
+#define HDLC_ESCAPE 0x7D
+
+#define HDLC_C_UI 0x03
+#define HDLC_C_P_BIT (1 << 4)
+#define HDLC_C_F_BIT (1 << 4)
+
+/* a low sercomm_dlci means high priority. A high DLCI means low priority */
+enum sercomm_dlci {
+ SC_DLCI_HIGHEST = 0,
+ SC_DLCI_DEBUG = 4,
+ SC_DLCI_L1A_L23 = 5,
+ SC_DLCI_LOADER = 9,
+ SC_DLCI_CONSOLE = 10,
+ SC_DLCI_ECHO = 128,
+ _SC_DLCI_MAX
+};
+
+void sercomm_init(void);
+int sercomm_initialized(void);
+
+/* User Interface: Tx */
+
+/* user interface for transmitting messages for a given DLCI */
+void sercomm_sendmsg(uint8_t dlci, struct msgb *msg);
+/* how deep is the Tx queue for a given DLCI */
+unsigned int sercomm_tx_queue_depth(uint8_t dlci);
+
+/* User Interface: Rx */
+
+/* receiving messages for a given DLCI */
+typedef void (*dlci_cb_t)(uint8_t dlci, struct msgb *msg);
+int sercomm_register_rx_cb(uint8_t dlci, dlci_cb_t cb);
+
+/* Driver Interface */
+
+/* fetch one octet of to-be-transmitted serial data. returns 0 if no more data */
+int sercomm_drv_pull(uint8_t *ch);
+/* the driver has received one byte, pass it into sercomm layer.
+ returns 1 in case of success, 0 in case of unrecognized char */
+int sercomm_drv_rx_char(uint8_t ch);
+
+static inline struct msgb *sercomm_alloc_msgb(unsigned int len)
+{
+ return msgb_alloc_headroom(len+4, 4, "sercomm_tx");
+}
+
+#endif /* _SERCOMM_H */
diff --git a/src/target/firmware/include/comm/sercomm_cons.h b/src/target/firmware/include/comm/sercomm_cons.h
new file mode 100644
index 00000000..11f66545
--- /dev/null
+++ b/src/target/firmware/include/comm/sercomm_cons.h
@@ -0,0 +1,10 @@
+#ifndef _SERCOMM_CONS_H
+#define _SERCOMM_CONS_H
+
+/* how large buffers do we allocate? */
+#define SERCOMM_CONS_ALLOC 256
+
+int sercomm_puts(const char *s);
+int sercomm_putchar(int c);
+
+#endif /* _SERCOMM_CONS_H */
diff --git a/src/target/firmware/include/comm/timer.h b/src/target/firmware/include/comm/timer.h
new file mode 100644
index 00000000..1996f666
--- /dev/null
+++ b/src/target/firmware/include/comm/timer.h
@@ -0,0 +1,77 @@
+/*
+ * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef TIMER_H
+#define TIMER_H
+
+#include <sys/time.h>
+
+#include <osmocom/core/linuxlist.h>
+
+#define HZ 100
+
+/**
+ * Timer management:
+ * - Create a struct osmo_timer_list
+ * - Fill out timeout and use osmo_timer_add or
+ * use osmo_timer_schedule to schedule a timer in
+ * x seconds and microseconds from now...
+ * - Use osmo_timer_del to remove the timer
+ *
+ * Internally:
+ * - We hook into select.c to give a timeval of the
+ * nearest timer. On already passed timers we give
+ * it a 0 to immediately fire after the select
+ * - osmo_timers_update will call the callbacks and remove
+ * the timers.
+ *
+ */
+struct osmo_timer_list {
+ struct llist_head entry;
+ unsigned long expires;
+
+ unsigned int active : 1;
+ unsigned int handled : 1;
+ unsigned int in_list : 1;
+
+ void (*cb)(void*);
+ void *data;
+};
+
+extern unsigned long volatile jiffies;
+
+/**
+ * timer management
+ */
+void osmo_timer_add(struct osmo_timer_list *timer);
+void osmo_timer_schedule(struct osmo_timer_list *timer, int miliseconds);
+void osmo_timer_del(struct osmo_timer_list *timer);
+int osmo_timer_pending(struct osmo_timer_list *timer);
+
+
+/**
+ * internal timer list management
+ */
+int osmo_timers_update(void);
+int osmo_timers_check(void);
+
+void timer_init(void);
+
+#endif
diff --git a/src/target/firmware/include/console.h b/src/target/firmware/include/console.h
new file mode 100644
index 00000000..7146e990
--- /dev/null
+++ b/src/target/firmware/include/console.h
@@ -0,0 +1,20 @@
+#ifndef _CONSOLE_H
+#define _CONSOLE_H
+
+/* This is the direct (IRQ driven) UART console, bypassing the HDLC layer.
+ * You should not need to call those functions unless you've decided to
+ * not use the HLDC layer or have a device with two UARTs */
+
+int cons_rb_append(const char *data, int len);
+int cons_puts(const char *s);
+int cons_putchar(char c);
+int cons_rb_flush(void);
+void cons_init(void);
+
+/* We want the console on UART 0 (IRDA UART) */
+#define CONS_UART_NR 0
+
+/* Size of the static ring-buffer that we keep for console print messages */
+#define CONS_RB_SIZE 4096
+
+#endif /* _CONSOLE_H */
diff --git a/src/target/firmware/include/ctors.h b/src/target/firmware/include/ctors.h
new file mode 100644
index 00000000..ee4c7b3e
--- /dev/null
+++ b/src/target/firmware/include/ctors.h
@@ -0,0 +1,16 @@
+#ifndef _CTORS_H
+#define _CTORS_H
+
+#if 0
+/* only supported by gcc 3.4 or later */
+#define __ctor_data __attribute__ ((constructor) (100))
+#define __ctor_board __attribute__ ((constructor) (200))
+#else
+#define __ctor_data __attribute__ ((constructor))
+#define __ctor_board __attribute__ ((constructor))
+#endif
+
+/* iterate over list of constructor functions and call each element */
+void do_global_ctors(const char *ctors_start, const char *ctors_end);
+
+#endif
diff --git a/src/target/firmware/include/ctype.h b/src/target/firmware/include/ctype.h
new file mode 100644
index 00000000..afa36392
--- /dev/null
+++ b/src/target/firmware/include/ctype.h
@@ -0,0 +1,54 @@
+#ifndef _LINUX_CTYPE_H
+#define _LINUX_CTYPE_H
+
+/*
+ * NOTE! This ctype does not handle EOF like the standard C
+ * library is required to.
+ */
+
+#define _U 0x01 /* upper */
+#define _L 0x02 /* lower */
+#define _D 0x04 /* digit */
+#define _C 0x08 /* cntrl */
+#define _P 0x10 /* punct */
+#define _S 0x20 /* white space (space/lf/tab) */
+#define _X 0x40 /* hex digit */
+#define _SP 0x80 /* hard space (0x20) */
+
+extern unsigned char _ctype[];
+
+#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
+
+#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
+#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
+#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
+#define isdigit(c) ((__ismask(c)&(_D)) != 0)
+#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
+#define islower(c) ((__ismask(c)&(_L)) != 0)
+#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
+#define ispunct(c) ((__ismask(c)&(_P)) != 0)
+#define isspace(c) ((__ismask(c)&(_S)) != 0)
+#define isupper(c) ((__ismask(c)&(_U)) != 0)
+#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
+
+#define isascii(c) (((unsigned char)(c))<=0x7f)
+#define toascii(c) (((unsigned char)(c))&0x7f)
+
+static inline unsigned char __tolower(unsigned char c)
+{
+ if (isupper(c))
+ c -= 'A'-'a';
+ return c;
+}
+
+static inline unsigned char __toupper(unsigned char c)
+{
+ if (islower(c))
+ c -= 'a'-'A';
+ return c;
+}
+
+#define tolower(c) __tolower(c)
+#define toupper(c) __toupper(c)
+
+#endif
diff --git a/src/target/firmware/include/debug.h b/src/target/firmware/include/debug.h
new file mode 100644
index 00000000..27c4185d
--- /dev/null
+++ b/src/target/firmware/include/debug.h
@@ -0,0 +1,31 @@
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+/*
+ * Check at compile time that something is of a particular type.
+ * Always evaluates to 1 so you may use it easily in comparisons.
+ */
+#define typecheck(type,x) \
+({ type __dummy; \
+ typeof(x) __dummy2; \
+ (void)(&__dummy == &__dummy2); \
+ 1; \
+})
+
+#ifdef DEBUG
+#define dputchar(x) putchar(x)
+#define dputs(x) puts(x)
+#define dphex(x,y) phex(x,y)
+#define printd(x, args ...) printf(x, ## args)
+#else
+#define dputchar(x)
+#define dputs(x)
+#define dphex(x,y)
+#define printd(x, args ...)
+#endif
+
+#endif /* _DEBUG_H */
diff --git a/src/target/firmware/include/defines.h b/src/target/firmware/include/defines.h
new file mode 100644
index 00000000..3c8732f9
--- /dev/null
+++ b/src/target/firmware/include/defines.h
@@ -0,0 +1,18 @@
+
+#ifndef _DEFINES_H
+#define _DEFINES_H
+
+#define __attribute_const__ __attribute__((__const__))
+
+/* type properties */
+#define __packed __attribute__((packed))
+#define __aligned(alignment) __attribute__((aligned(alignment)))
+#define __unused __attribute__((unused))
+
+/* linkage */
+#define __section(name) __attribute__((section(name)))
+
+/* force placement in zero-waitstate memory */
+#define __ramtext __section(".ramtext")
+
+#endif /* !_DEFINES_H */
diff --git a/src/target/firmware/include/delay.h b/src/target/firmware/include/delay.h
new file mode 100644
index 00000000..0d6f3efd
--- /dev/null
+++ b/src/target/firmware/include/delay.h
@@ -0,0 +1,7 @@
+#ifndef delay_h
+#define delay_h
+
+void delay_ms(unsigned int ms);
+void delay_us(unsigned int us);
+
+#endif
diff --git a/src/target/firmware/include/fb/fb_bw8.h b/src/target/firmware/include/fb/fb_bw8.h
new file mode 100644
index 00000000..c77fa71f
--- /dev/null
+++ b/src/target/firmware/include/fb/fb_bw8.h
@@ -0,0 +1,51 @@
+#ifndef FB_BW8_H
+#define FB_BW8_H
+
+/* 8bit monochrome framebuffer, organized with 8 stacked pixels
+ per byte, backed by local memory. fb_bw8.c lists functions that
+ are common to simmilar organized displays. */
+
+/*
+ Sketch of Memory Layout
+ Left Upper Corner of Display
+
+ col0 col2
+ col1
+ +-------------
+ 1st row: | A0 B0 C0
+ 2nd row: | A1 B1 C1
+ ...
+ 7th row: | A6 B6 C6
+ 8th row: | A7 B7 C7
+ 9th row: | Q0 R0 S0
+ 10th row: | Q1 R1 S1 ...
+ ...
+
+ Backing store (and internal display memory?) looks like...
+
+ uint8_t mem[] = { A, B, C, .... Q, R, S, ... }
+
+ We work on a in-memory copy of the framebuffer and only
+ update the physical display on demand. The damage window
+ has two corners, left upper inclusive x1,y1 and right
+ lower x2,y2 exclusive. So dirty pixels are defined to
+ be x1 <= x_pixel < x2 and y1 <= y_pixel < y2.
+*/
+
+/* data specific to a bw8-type framebuffer as described above */
+
+struct fb_bw8 {
+ uint8_t *mem; /* set to backingstore memory */
+ uint16_t damage_x1,damage_y1; /* current damage window, ul */
+ uint16_t damage_x2,damage_y2; /* current damage window, lr */
+};
+
+extern struct fb_bw8 *fb_bw8; /* symbol defined by the specific LCD driver */
+
+extern void fb_bw8_clear();
+extern void fb_bw8_boxto(uint16_t x,uint16_t y); /* draw a box from cursor to x,y */
+extern void fb_bw8_lineto(uint16_t x,uint16_t y); /* draw a line from cursor to x,y */
+
+extern int fb_bw8_putstr(char *str,int maxwidth);
+
+#endif
diff --git a/src/target/firmware/include/fb/fb_rgb332.h b/src/target/firmware/include/fb/fb_rgb332.h
new file mode 100644
index 00000000..4df44e4e
--- /dev/null
+++ b/src/target/firmware/include/fb/fb_rgb332.h
@@ -0,0 +1,47 @@
+#ifndef FB_RGB332_H
+#define FB_RGB332_H
+
+/* RGB framebuffer with 1 byte per pixel, bits mapped as RRRGGGBB */
+
+struct fb_rgb332 {
+ uint8_t *mem; /* set to backingstore memory */
+ uint16_t damage_x1,damage_y1; /* current damage window, ul (incl) */
+ uint16_t damage_x2,damage_y2; /* current damage window, lr (excl) */
+};
+
+extern void fb_rgb332_clear();
+
+/* draw a box from cursor to x,y */
+extern void fb_rgb332_boxto(uint16_t x,uint16_t y);
+/* draw a line from cursor to x,y */
+extern void fb_rgb332_lineto(uint16_t x,uint16_t y);
+
+/* put string str onto framebuffer with line (bottom
+ left pixel of, e.g. "m") starting at cursor.
+ Maximum width consumed is maxwidth, actual width
+ needed is returned */
+extern int fb_rgb332_putstr(char *str,int maxwidth);
+
+extern struct fb_rgb332 *fb_rgb332;
+
+/* this convenience function can be used if you choose to
+ * back a RGB565 display with a RGB332 framebuffer to conserve
+ * ARM memory. It converts a rgb332 value to rgb565 as indicated
+ * in the comments. */
+
+static inline uint16_t
+rgb332_to_565(uint8_t rgb332){
+
+ uint8_t red = (rgb332 & 0xe0) >> 5 ; // rrr. .... -> .... .rrr
+ uint8_t green = ((rgb332 & 0x1c) >> 2); // ...g gg.. -> .... .ggg
+ uint8_t blue = rgb332 & 0x03; // .... ..bb -> .... ..bb
+
+ red = (red << 2) | (red >> 1); /* .....210 -> ...21021 */
+ green = (green << 3) | (green); /* .....210 -> ..210210 */
+ blue = (blue << 3) | (blue << 1) | (blue >> 1); /* ......10 -> ...10101 */
+
+ /* rrrrrggg gggbbbbb */
+ return (red << 11) | (green << 5) | blue;
+}
+
+#endif
diff --git a/src/target/firmware/include/fb/font.h b/src/target/firmware/include/fb/font.h
new file mode 100644
index 00000000..9dee8ffb
--- /dev/null
+++ b/src/target/firmware/include/fb/font.h
@@ -0,0 +1,82 @@
+#ifndef _FB_FONT_H
+#define _FB_FONT_H
+
+#include <stdint.h>
+#include <unistd.h>
+
+/*
+ Example:
+ Font Helvetica 14
+
+
+ Character W ('X' and '.' is the character font data)
+
+ X.....X......&...
+ X.....X......X...
+ X....X.X.....X...
+ .X...X.X....X....
+ .X...X.X....X....
+ .X...X.X....X....
+ ..X.X....X.X.....
+ ..X.X....X.X.....
+ ..X.X....X.X.....
+ ...X......X......
+ @%..X......X...$..
+ <---dwidth---->
+
+ @ is the cursor position (origin) for this character
+ $ is the cursor position (origin) for the next character
+ % is the character boundingbox origin,
+ & is the character boundingbox top right corner
+
+ */
+
+/* data for char c is found by getting the index into the
+ chardata array from the charoffs array.
+
+ if charoffs[c] == FB_FONT_NOCHAR, then this glyph does
+ not exist! Better use the convenience function fb_font_get_char below! */
+
+#define FB_FONT_NOCHAR 0xffff
+
+struct fb_font {
+ int8_t height; /* total height of font */
+ int8_t ascent; /* topmost pixel is "ascend" above
+ current cursor position y */
+ uint8_t firstchar,lastchar; /* range of characters in font (iso8859-1) */
+ uint8_t const *chardata;
+ uint16_t const *charoffs; /* byte offsets relative to chardata */
+ uint8_t const *widths; /* widths for characters */
+};
+
+struct fb_char {
+ int8_t width;
+ int8_t bbox_w,bbox_h,bbox_x,bbox_y;
+ uint8_t data[0];
+};
+
+/* there are currently 6 fonts available, Helvetica 8, 14, 24 point
+ in bold and regular shapes. The following enum has to match the
+ order of the array fb_fonts in framebuffer.c!
+*/
+
+enum fb_font_id {
+// FB_FONT_4X6,
+// FB_FONT_5X8,
+ FB_FONT_HELVR08,
+// FB_FONT_HELVR14
+// FB_FONT_HELVR24,
+// FB_FONT_HELVB08,
+ FB_FONT_HELVB14,
+// FB_FONT_HELVB24,
+ FB_FONT_C64,
+ FB_FONT_SYMBOLS,
+};
+
+extern const struct fb_font *fb_fonts[]; // note: has to match fb_font_id enum!
+
+extern const struct fb_char *
+fb_font_get_char(const struct fb_font *fnt,unsigned char c);
+
+#endif
+
diff --git a/src/target/firmware/include/fb/framebuffer.h b/src/target/firmware/include/fb/framebuffer.h
new file mode 100644
index 00000000..e765b36d
--- /dev/null
+++ b/src/target/firmware/include/fb/framebuffer.h
@@ -0,0 +1,128 @@
+#ifndef _FB_FRAMEBUFFER_H
+#define _FB_FRAMEBUFFER_H
+
+#include <fb/font.h>
+#include <stdint.h>
+
+/* color is encoded as <special><red><green><blue> */
+/* if a color is "special", then the RGB components most likely
+ don't make sense. Use "special" colours when you have to
+ mask out bits with transparency or you have to encode
+ colours in a fixed color palette... */
+
+#define FB_COLOR_WHITE 0x00ffffffU
+#define FB_COLOR_BLACK 0x00000000U
+#define FB_COLOR_TRANSP 0x01ffffffU
+
+#define FB_COLOR_RGB(r,g,b) ((((r) & 0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))
+#define FB_COLOR_RED FB_COLOR_RGB(0xff,0x00,0x00)
+#define FB_COLOR_GREEN FB_COLOR_RGB(0x00,0xff,0x00)
+#define FB_COLOR_BLUE FB_COLOR_RGB(0x00,0x00,0xff)
+
+/* encode */
+
+/* decode */
+#define FB_COLOR_IS_SPECIAL(v) (!!((v) & 0xff000000U))
+#define FB_COLOR_TO_R(v) (((v)>>16) & 0xff)
+#define FB_COLOR_TO_G(v) (((v)>> 8) & 0xff)
+#define FB_COLOR_TO_B(v) ( (v) & 0xff)
+
+struct framebuffer {
+ char name[8]; // keep it short!
+ void (*init)(); // (re)initialize
+ void (*clear)(); // clear display
+ void (*boxto)(uint16_t x,uint16_t y); // draw box to xy
+ void (*lineto)(uint16_t x,uint16_t y); // draw line to xy
+ int (*putstr)(char *c,int maxwidth); // put text in current font to fb
+ void (*flush)(); // flush changes
+
+ uint16_t width,height; // width/height of fb
+ uint16_t cursor_x,cursor_y; // current cursor
+ uint32_t fg_color,bg_color; // current fg/bg color
+ enum fb_font_id font; // current font
+};
+
+/* there is a single framebuffer, the specific driver defines
+ the "framebuffer" symbol */
+extern struct framebuffer *framebuffer;
+
+static inline void
+fb_init(){
+ framebuffer->init();
+}
+
+static inline void
+fb_clear(){
+ framebuffer->clear();
+}
+
+static inline void
+fb_boxto(uint16_t x,uint16_t y){
+ framebuffer->boxto(x,y);
+}
+
+static inline void
+fb_lineto(uint16_t x,uint16_t y){
+ framebuffer->lineto(x,y);
+}
+
+static inline int
+fb_putstr(char *str,int maxwidth){
+ return framebuffer->putstr(str,maxwidth);
+}
+
+static inline void
+fb_flush(){
+ framebuffer->flush();
+}
+
+static inline void
+fb_gotoxy(uint16_t x,uint16_t y){
+ framebuffer->cursor_x = x;
+ framebuffer->cursor_y = y;
+}
+
+static inline void
+fb_setfg(uint32_t color){
+ framebuffer->fg_color = color;
+}
+
+static inline void
+fb_setbg(uint32_t color){
+ framebuffer->bg_color = color;
+}
+
+static inline void
+fb_setfont(enum fb_font_id fid){
+ framebuffer->font = fid;
+}
+
+/* utility function: limit coordinates to area of framebuffer */
+static inline void
+fb_limit_fb_range(uint16_t *x,uint16_t *y){
+ if(*x >= framebuffer->width)
+ *x = framebuffer->width - 1;
+ if(*y >= framebuffer->height)
+ *y = framebuffer->height - 1;
+}
+
+/* utility function: limit box coordinates to area of framebuffer
+ and make sure that x1y1 is left upper edge, x2y2 is right lower */
+static inline void
+fb_sanitize_box(uint16_t *x1,uint16_t *y1,uint16_t *x2,uint16_t *y2){
+ fb_limit_fb_range(x1,y1);
+ fb_limit_fb_range(x2,y2);
+ if(*x1 > *x2){
+ uint16_t tmp = *x1;
+ *x1 = *x2;
+ *x2 = tmp;
+ }
+ if(*y1 > *y2){
+ uint16_t tmp = *y1;
+ *y1 = *y2;
+ *y2 = tmp;
+ }
+}
+
+#endif
+
diff --git a/src/target/firmware/include/flash/cfi_flash.h b/src/target/firmware/include/flash/cfi_flash.h
new file mode 100644
index 00000000..9d8b33ae
--- /dev/null
+++ b/src/target/firmware/include/flash/cfi_flash.h
@@ -0,0 +1,41 @@
+
+#ifndef _CFI_FLASH_H
+#define _CFI_FLASH_H
+
+#include <stdint.h>
+
+#define FLASH_MAX_REGIONS 4
+
+typedef struct {
+ void *fr_base;
+ size_t fr_bnum;
+ size_t fr_bsize;
+} flash_region_t;
+
+typedef struct {
+ void *f_base;
+ size_t f_size;
+
+ size_t f_nregions;
+ flash_region_t f_regions[FLASH_MAX_REGIONS];
+} flash_t;
+
+typedef enum {
+ FLASH_UNLOCKED = 0,
+ FLASH_LOCKED,
+ FLASH_LOCKED_DOWN
+} flash_lock_t;
+
+int flash_init(flash_t *flash, void *base_addr);
+
+flash_lock_t flash_block_getlock(flash_t *flash, uint32_t block_offset);
+
+int flash_block_unlock(flash_t *flash, uint32_t block_offset);
+int flash_block_lock(flash_t *flash, uint32_t block_offset);
+int flash_block_lockdown(flash_t *flash, uint32_t block_offset);
+
+int flash_block_erase(flash_t *flash, uint32_t block_offset);
+
+int flash_program(flash_t *flash, uint32_t dst_offset, void *src, uint32_t nbytes);
+
+#endif
diff --git a/src/target/firmware/include/i2c.h b/src/target/firmware/include/i2c.h
new file mode 100644
index 00000000..37097a85
--- /dev/null
+++ b/src/target/firmware/include/i2c.h
@@ -0,0 +1,7 @@
+#ifndef _I2C_H
+#define _I2C_H
+
+int i2c_write(uint8_t chip, uint32_t addr, int alen, const uint8_t *buffer, int len);
+void i2c_init(int speed, int slaveadd);
+
+#endif /* I2C_H */
diff --git a/src/target/firmware/include/keypad.h b/src/target/firmware/include/keypad.h
new file mode 100644
index 00000000..e2e6519f
--- /dev/null
+++ b/src/target/firmware/include/keypad.h
@@ -0,0 +1,66 @@
+#ifndef _KEYPAD_H
+#define _KEYPAD_H
+
+enum buttons {
+ BTN_0 = 0x00002000,
+ BTN_1 = 0x00008000,
+ BTN_2 = 0x00000400,
+ BTN_3 = 0x00000020,
+ BTN_4 = 0x00010000,
+ BTN_5 = 0x00000800,
+ BTN_6 = 0x00000040,
+ BTN_7 = 0x00020000,
+ BTN_8 = 0x00001000,
+ BTN_9 = 0x00000080,
+ BTN_STAR = 0x00040000,
+ BTN_HASH = 0x00000100,
+ BTN_MENU = 0x00004000,
+ BTN_LEFT_SB = 0x00080000,
+ BTN_RIGHT_SB = 0x00000200,
+ BTN_UP = 0x00000002,
+ BTN_DOWN = 0x00000004,
+ BTN_LEFT = 0x00000008,
+ BTN_RIGHT = 0x00000010,
+ BTN_OK = 0x00000001,
+ BTN_POWER = 0x01000000,
+};
+
+enum key_codes {
+ KEY_0 = 0,
+ KEY_1,
+ KEY_2,
+ KEY_3,
+ KEY_4,
+ KEY_5,
+ KEY_6,
+ KEY_7,
+ KEY_8,
+ KEY_9,
+ KEY_STAR, //*
+ KEY_HASH, //#
+ KEY_MENU, //center of directional keys
+ KEY_LEFT_SB, //softbutton
+ KEY_RIGHT_SB, //softbutton
+ KEY_UP,
+ KEY_DOWN,
+ KEY_LEFT,
+ KEY_RIGHT,
+ KEY_OK, //green off-hook
+ KEY_POWER, //red on-hook
+ KEY_INV = 0xFF
+};
+
+enum key_states {
+ PRESSED,
+ RELEASED,
+};
+
+void keypad_init(uint8_t interrupts);
+
+void keypad_poll();
+
+typedef void (*key_handler_t)(enum key_codes code, enum key_states state);
+
+void keypad_set_handler(key_handler_t handler);
+
+#endif /* KEYPAD_H */
diff --git a/src/target/firmware/include/layer1/afc.h b/src/target/firmware/include/layer1/afc.h
new file mode 100644
index 00000000..8b43f8aa
--- /dev/null
+++ b/src/target/firmware/include/layer1/afc.h
@@ -0,0 +1,18 @@
+#ifndef _L1_AFC_H
+#define _L1_AFC_H
+
+#define AFC_SNR_THRESHOLD 2560 /* 2.5 dB in fx6.10 */
+
+/* Input a frequency error sample into the AFC averaging */
+void afc_input(int32_t freq_error, uint16_t arfcn, int valid);
+
+/* Update the AFC with a frequency error, bypassing averaging */
+void afc_correct(int16_t freq_error, uint16_t arfcn);
+
+/* Update DSP with new AFC DAC value to be used for next TDMA frame */
+void afc_load_dsp(void);
+
+/* Reset the AFC to its initial DAC value */
+void afc_reset(void);
+
+#endif
diff --git a/src/target/firmware/include/layer1/agc.h b/src/target/firmware/include/layer1/agc.h
new file mode 100644
index 00000000..2b7e46e9
--- /dev/null
+++ b/src/target/firmware/include/layer1/agc.h
@@ -0,0 +1,7 @@
+#ifndef _L1_AGC_H
+#define _L1_AGC_H
+
+#define to_dbm8(x) ((x)*8)
+int16_t agc_inp_dbm8_by_pm(int16_t pm);
+
+#endif /* _L1_AGC_H */
diff --git a/src/target/firmware/include/layer1/apc.h b/src/target/firmware/include/layer1/apc.h
new file mode 100644
index 00000000..3d73c23e
--- /dev/null
+++ b/src/target/firmware/include/layer1/apc.h
@@ -0,0 +1,10 @@
+#ifndef _L1_APC_H
+#define _L1_APC_H
+
+/* determine the AUXAPC value by the Tx Power Level */
+int16_t apc_tx_dbm2auxapc(enum gsm_band band, int8_t dbm);
+
+/* determine the AUXAPC value by the Tx Power Level */
+int16_t apc_tx_pwrlvl2auxapc(enum gsm_band band, uint8_t lvl);
+
+#endif
diff --git a/src/target/firmware/include/layer1/async.h b/src/target/firmware/include/layer1/async.h
new file mode 100644
index 00000000..de996a67
--- /dev/null
+++ b/src/target/firmware/include/layer1/async.h
@@ -0,0 +1,62 @@
+#ifndef _L1_ASYNC_H
+#define _L1_ASYNC_H
+
+#include <osmocom/core/msgb.h>
+
+#include <layer1/mframe_sched.h>
+
+#if 0
+NOTE: Re-enabling interrupts causes an IRQ while processing the same IRQ.
+ Use local_firq_save and local_irq_restore instead!
+
+/* When altering data structures used by L1 Sync part, we need to
+ * make sure to temporarily disable IRQ/FIQ to keep data consistent */
+static inline void l1a_lock_sync(void)
+{
+ arm_disable_interrupts();
+}
+
+static inline void l1a_unlock_sync(void)
+{
+ arm_enable_interrupts();
+}
+#endif
+
+/* safely enable a message into the L1S TX queue */
+void l1a_txq_msgb_enq(struct llist_head *queue, struct msgb *msg);
+void l1a_meas_msgb_set(struct msgb *msg);
+
+/* safely count messages in the L1S TX queue */
+int l1a_txq_msgb_count(struct llist_head *queue);
+
+/* flush all pending msgb */
+void l1a_txq_msgb_flush(struct llist_head *queue);
+
+/* request a RACH */
+void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra);
+
+/* schedule frequency change */
+void l1a_freq_req(uint32_t fn_sched);
+
+/* Enable a repeating multiframe task */
+void l1a_mftask_enable(enum mframe_task task);
+
+/* Disable a repeating multiframe task */
+void l1a_mftask_disable(enum mframe_task task);
+
+/* Set the mask for repeating multiframe tasks */
+void l1a_mftask_set(uint32_t tasks);
+
+/* Set TCH mode */
+uint8_t l1a_tch_mode_set(uint8_t mode);
+
+/* Set Audio routing mode */
+uint8_t l1a_audio_mode_set(uint8_t mode);
+
+/* Execute pending L1A completions */
+void l1a_compl_execute(void);
+
+/* Initialize asynchronous part of Layer1 */
+void l1a_init(void);
+
+#endif
diff --git a/src/target/firmware/include/layer1/avg.h b/src/target/firmware/include/layer1/avg.h
new file mode 100644
index 00000000..6c5de172
--- /dev/null
+++ b/src/target/firmware/include/layer1/avg.h
@@ -0,0 +1,23 @@
+#ifndef _L1_AVG_H
+#define _L1_AVG_H
+
+struct running_avg {
+ /* configuration */
+ uint16_t period; /* over how many samples to average */
+ uint16_t min_valid;
+
+ int32_t acc_val;
+ uint16_t num_samples; /* how often did we try to sample? */
+ uint16_t num_samples_valid; /* how often did we receive valid samples? */
+
+ void (*outfn)(struct running_avg *, int32_t avg);
+ void *priv;
+};
+
+/* input a new sample into the averaging process */
+void runavg_input(struct running_avg *ravg, int32_t val, int valid);
+
+/* check if sufficient samples have been obtained, and call outfn() */
+int runavg_check_output(struct running_avg *ravg);
+
+#endif /* _AVG_H */
diff --git a/src/target/firmware/include/layer1/l23_api.h b/src/target/firmware/include/layer1/l23_api.h
new file mode 100644
index 00000000..e4a3fd0a
--- /dev/null
+++ b/src/target/firmware/include/layer1/l23_api.h
@@ -0,0 +1,18 @@
+#ifndef _L1_L23_API_H
+#define _L1_L23_API_H
+
+#include <stdint.h>
+#include <osmocom/core/msgb.h>
+#include <l1ctl_proto.h>
+
+void l1a_l23api_init(void);
+void l1a_l23_handler(void);
+void l1_queue_for_l2(struct msgb *msg);
+struct msgb *l1ctl_msgb_alloc(uint8_t msg_type);
+struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr, uint16_t arfcn);
+extern void (*l1a_l23_tx_cb)(struct msgb *msg);
+void l1a_l23_rx(uint8_t dlci, struct msgb *msg);
+
+void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type);
+
+#endif /* _L1_L23_API_H */
diff --git a/src/target/firmware/include/layer1/mframe_sched.h b/src/target/firmware/include/layer1/mframe_sched.h
new file mode 100644
index 00000000..ecdb1ec8
--- /dev/null
+++ b/src/target/firmware/include/layer1/mframe_sched.h
@@ -0,0 +1,68 @@
+#ifndef _L1_MFRAME_SCHED_H
+#define _L1_MFRAME_SCHED_H
+
+#include <stdint.h>
+
+enum mframe_task {
+ MF_TASK_BCCH_NORM,
+ MF_TASK_BCCH_EXT,
+ MF_TASK_CCCH,
+ MF_TASK_CCCH_COMB,
+
+ MF_TASK_SDCCH4_0,
+ MF_TASK_SDCCH4_1,
+ MF_TASK_SDCCH4_2,
+ MF_TASK_SDCCH4_3,
+
+ MF_TASK_SDCCH8_0,
+ MF_TASK_SDCCH8_1,
+ MF_TASK_SDCCH8_2,
+ MF_TASK_SDCCH8_3,
+ MF_TASK_SDCCH8_4,
+ MF_TASK_SDCCH8_5,
+ MF_TASK_SDCCH8_6,
+ MF_TASK_SDCCH8_7,
+
+ MF_TASK_TCH_F_EVEN,
+ MF_TASK_TCH_F_ODD,
+ MF_TASK_TCH_H_0,
+ MF_TASK_TCH_H_1,
+
+ MF_TASK_NEIGH_PM51_C0T0,
+ MF_TASK_NEIGH_PM51,
+ MF_TASK_NEIGH_PM26E,
+ MF_TASK_NEIGH_PM26O,
+
+ /* Test task: send Normal Burst in all timeslots */
+ MF_TASK_UL_ALL_NB,
+};
+
+enum mf_sched_item_flag {
+ MF_F_SACCH = (1 << 0),
+};
+
+/* The scheduler itself */
+struct mframe_scheduler {
+ uint32_t tasks;
+ uint32_t tasks_tgt;
+ uint32_t safe_fn;
+};
+
+uint8_t mframe_task2chan_nr(enum mframe_task mft, uint8_t ts);
+
+/* Enable a specific task */
+void mframe_enable(enum mframe_task task_id);
+
+/* Disable a specific task */
+void mframe_disable(enum mframe_task task_id);
+
+/* Replace the current active set by the new one */
+void mframe_set(uint32_t tasks);
+
+/* Schedule mframe_sched_items according to current MF TASK list */
+void mframe_schedule(void);
+
+/* reset the scheduler, disabling all tasks */
+void mframe_reset(void);
+
+#endif /* _MFRAME_SCHED_H */
diff --git a/src/target/firmware/include/layer1/prim.h b/src/target/firmware/include/layer1/prim.h
new file mode 100644
index 00000000..30c51ae6
--- /dev/null
+++ b/src/target/firmware/include/layer1/prim.h
@@ -0,0 +1,34 @@
+#ifndef _L1_PRIM_H
+#define _L1_PRIM_H
+
+#include <stdint.h>
+
+#include <layer1/tdma_sched.h>
+
+struct l1ctl_fbsb_req;
+
+/* Utils */
+const uint8_t *pu_get_idle_frame(void);
+void pu_update_rx_level(uint8_t rx_level);
+const uint8_t *pu_get_meas_frame(void);
+
+/* Primitives tests/requests */
+void l1s_fb_test(uint8_t base_fn, uint8_t fb_mode);
+void l1s_sb_test(uint8_t base_fn);
+void l1s_pm_test(uint8_t base_fn, uint16_t arfcn);
+void l1s_nb_test(uint8_t base_fn);
+
+void l1s_fbsb_req(uint8_t base_fn, struct l1ctl_fbsb_req *req);
+void l1a_freq_req(uint32_t fn_sched);
+void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra);
+
+/* Primitives raw scheduling sets */
+extern const struct tdma_sched_item nb_sched_set[];
+extern const struct tdma_sched_item nb_sched_set_ul[];
+
+extern const struct tdma_sched_item tch_sched_set[];
+extern const struct tdma_sched_item tch_a_sched_set[];
+extern const struct tdma_sched_item tch_d_sched_set[];
+extern const struct tdma_sched_item neigh_pm_sched_set[];
+
+#endif /* _L1_PRIM_H */
diff --git a/src/target/firmware/include/layer1/rfch.h b/src/target/firmware/include/layer1/rfch.h
new file mode 100644
index 00000000..344523c3
--- /dev/null
+++ b/src/target/firmware/include/layer1/rfch.h
@@ -0,0 +1,9 @@
+#ifndef _L1_RFCH_H
+#define _L1_RFCH_H
+
+struct gsm_time;
+
+void rfch_get_params(struct gsm_time *t,
+ uint16_t *arfcn_p, uint8_t *tsc_p, uint8_t *tn_p);
+
+#endif /* _L1_RFCH_H */
diff --git a/src/target/firmware/include/layer1/sched_gsmtime.h b/src/target/firmware/include/layer1/sched_gsmtime.h
new file mode 100644
index 00000000..c40359ea
--- /dev/null
+++ b/src/target/firmware/include/layer1/sched_gsmtime.h
@@ -0,0 +1,24 @@
+#ifndef _L1_SCHED_GSMTIME_H
+#define _L1_SCHED_GSMTIME_H
+
+#include <stdint.h>
+#include <osmocom/core/linuxlist.h>
+
+struct sched_gsmtime_event {
+ struct llist_head list;
+ const struct tdma_sched_item *si;
+ uint32_t fn;
+ uint16_t p3; /* parameter for TDMA scheduler */
+};
+
+/* initialize the GSMTIME scheduler */
+void sched_gsmtime_init(void);
+
+/* Scheduling of a single event at a givnen GSM time */
+int sched_gsmtime(const struct tdma_sched_item *si, uint32_t fn, uint16_t p3);
+
+/* execute all GSMTIME one-shot events pending for 'current_fn' */
+int sched_gsmtime_execute(uint32_t current_fn);
+
+void sched_gsmtime_reset(void);
+#endif
diff --git a/src/target/firmware/include/layer1/sync.h b/src/target/firmware/include/layer1/sync.h
new file mode 100644
index 00000000..dae85a1a
--- /dev/null
+++ b/src/target/firmware/include/layer1/sync.h
@@ -0,0 +1,204 @@
+#ifndef _L1_SYNC_H
+#define _L1_SYNC_H
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/mframe_sched.h>
+#include <l1ctl_proto.h>
+
+/* structure representing L1 sync information about a cell */
+struct l1_cell_info {
+ /* on which ARFCN (+band) is the cell? */
+ uint16_t arfcn;
+ /* what's the BSIC of the cell (from SCH burst decoding) */
+ uint8_t bsic;
+ /* Combined or non-combined CCCH */
+ uint8_t ccch_mode; /* enum ccch_mode */
+ /* whats the delta of the cells current GSM frame number
+ * compared to our current local frame number */
+ int32_t fn_offset;
+ /* how much does the TPU need adjustment (delta) to synchronize
+ * with the cells burst */
+ uint32_t time_alignment;
+ /* FIXME: should we also store the AFC value? */
+};
+
+enum l1s_chan {
+ L1S_CHAN_MAIN,
+ L1S_CHAN_SACCH,
+ L1S_CHAN_TRAFFIC,
+ _NUM_L1S_CHAN
+};
+
+enum l1_compl {
+ L1_COMPL_FB,
+ L1_COMPL_RACH,
+ L1_COMPL_TX_NB,
+ L1_COMPL_TX_TCH,
+};
+
+typedef void l1_compl_cb(enum l1_compl c);
+
+#define L1S_NUM_COMPL 32
+#define L1S_NUM_NEIGH_CELL 6
+
+struct l1s_h0 {
+ uint16_t arfcn;
+};
+
+struct l1s_h1 {
+ uint8_t hsn;
+ uint8_t maio;
+ uint8_t n;
+ uint16_t ma[64];
+};
+
+struct l1s_state {
+ struct gsm_time current_time; /* current GSM time */
+ struct gsm_time next_time; /* GSM time at next TMDMA irq */
+
+ /* the cell on which we are camping right now */
+ struct l1_cell_info serving_cell;
+
+ /* neighbor cell sync info */
+ struct l1_cell_info neigh_cell[L1S_NUM_NEIGH_CELL];
+
+ /* TDMA scheduler */
+ struct tdma_scheduler tdma_sched;
+
+ /* Multiframe scheduler */
+ struct mframe_scheduler mframe_sched;
+
+ /* The current TPU offset register */
+ uint32_t tpu_offset;
+ int32_t tpu_offset_correction;
+
+ /* TX parameters */
+ int8_t ta;
+ uint8_t tx_power;
+
+ /* TCH */
+ uint8_t tch_mode;
+ uint8_t tch_sync;
+ uint8_t audio_mode;
+
+ /* Transmit queues of pending packets for main DCCH and ACCH */
+ struct llist_head tx_queue[_NUM_L1S_CHAN];
+ struct msgb *tx_meas;
+
+ /* Which L1A completions are scheduled right now */
+ uint32_t scheduled_compl;
+ /* callbacks for each of the completions */
+ l1_compl_cb *completion[L1S_NUM_COMPL];
+
+ /* Structures below are for L1-task specific parameters, used
+ * to communicate between l1-sync and l1-async (l23_api) */
+ struct {
+ uint8_t mode; /* FB_MODE 0/1 */
+ } fb;
+
+ struct {
+ /* power measurement l1 task */
+ unsigned int mode;
+ union {
+ struct {
+ uint16_t arfcn_start;
+ uint16_t arfcn_next;
+ uint16_t arfcn_end;
+ } range;
+ };
+ struct msgb *msg;
+ } pm;
+
+ struct {
+ uint8_t ra;
+ } rach;
+
+ struct {
+ enum {
+ GSM_DCHAN_NONE = 0,
+ GSM_DCHAN_SDCCH_4,
+ GSM_DCHAN_SDCCH_8,
+ GSM_DCHAN_TCH_H,
+ GSM_DCHAN_TCH_F,
+ GSM_DCHAN_UNKNOWN,
+ } type;
+
+ uint8_t scn;
+ uint8_t tsc;
+ uint8_t tn;
+ uint8_t h;
+
+ union {
+ struct l1s_h0 h0;
+ struct l1s_h1 h1;
+ };
+
+ uint8_t st_tsc;
+ uint8_t st_tn;
+ uint8_t st_h;
+
+ union {
+ struct l1s_h0 st_h0;
+ struct l1s_h1 st_h1;
+ };
+ } dedicated;
+
+ /* neighbour cell power measurement process */
+ struct {
+ uint8_t n, second;
+ uint8_t pos;
+ uint8_t running;
+ uint16_t band_arfcn[64];
+ uint8_t tn[64];
+ uint8_t level[64];
+ } neigh_pm;
+};
+
+extern struct l1s_state l1s;
+
+struct l1s_meas_hdr {
+ uint16_t snr; /* signal/noise ratio */
+ int16_t toa_qbit; /* time of arrival (qbits) */
+ int16_t pm_dbm8; /* power level in dbm/8 */
+ int16_t freq_err; /* Frequency error in Hz */
+};
+
+int16_t l1s_snr_int(uint16_t snr);
+uint16_t l1s_snr_fract(uint16_t snr);
+
+void l1s_dsp_abort(void);
+
+void l1s_tx_apc_helper(uint16_t arfcn);
+
+/* schedule a completion */
+void l1s_compl_sched(enum l1_compl c);
+
+void l1s_init(void);
+
+/* reset the layer1 as part of synchronizing to a new cell */
+void l1s_reset(void);
+
+/* init.c */
+void layer1_init(void);
+
+/* A debug macro to print every TDMA frame */
+#ifdef DEBUG_EVERY_TDMA
+#define putchart(x) putchar(x)
+#else
+#define putchart(x)
+#endif
+
+/* Convert an angle in fx1.15 notatinon into Hz */
+#define BITFREQ_DIV_2PI 43104 /* 270kHz / 2 * pi */
+#define BITFREQ_DIV_PI 86208 /* 270kHz / pi */
+#define ANG2FREQ_SCALING (2<<15) /* 2^15 scaling factor for fx1.15 */
+#define ANGLE_TO_FREQ(angle) ((int16_t)angle * BITFREQ_DIV_PI / ANG2FREQ_SCALING)
+
+void l1s_reset_hw(void);
+void synchronize_tdma(struct l1_cell_info *cinfo);
+void l1s_time_inc(struct gsm_time *time, uint32_t delta_fn);
+void l1s_time_dump(const struct gsm_time *time);
+
+#endif /* _L1_SYNC_H */
diff --git a/src/target/firmware/include/layer1/tdma_sched.h b/src/target/firmware/include/layer1/tdma_sched.h
new file mode 100644
index 00000000..f58d59bb
--- /dev/null
+++ b/src/target/firmware/include/layer1/tdma_sched.h
@@ -0,0 +1,73 @@
+#ifndef _L1_TDMA_SCHED_H
+#define _L1_TDMA_SCHED_H
+
+#include <stdint.h>
+
+/* TDMA scheduler */
+
+/* The idea of this scheduler is that we have a circular buffer of buckets,
+ * where each bucket corresponds to one future TDMA frame [interrupt]. Each
+ * bucket contains of a list of callbacks which are executed when the bucket
+ * index reaches that particular bucket. */
+
+#define TDMASCHED_NUM_FRAMES 25
+#define TDMASCHED_NUM_CB 8
+
+#define TDMA_IFLG_TPU (1<<0)
+#define TDMA_IFLG_DSP (1<<1)
+
+typedef int tdma_sched_cb(uint8_t p1, uint8_t p2, uint16_t p3);
+
+/* A single item in a TDMA scheduler bucket */
+struct tdma_sched_item {
+ tdma_sched_cb *cb;
+ uint8_t p1;
+ uint8_t p2;
+ uint16_t p3;
+ int16_t prio;
+ uint16_t flags; /* TDMA_IFLG_xxx */
+};
+
+/* A bucket inside the TDMA scheduler */
+struct tdma_sched_bucket {
+ struct tdma_sched_item item[TDMASCHED_NUM_CB];
+ uint8_t num_items;
+};
+
+/* The scheduler itself, consisting of buckets and a current index */
+struct tdma_scheduler {
+ struct tdma_sched_bucket bucket[TDMASCHED_NUM_FRAMES];
+ uint8_t cur_bucket;
+};
+
+/* Schedule an item at 'frame_offset' TDMA frames in the future */
+int tdma_schedule(uint8_t frame_offset, tdma_sched_cb *cb,
+ uint8_t p1, uint8_t p2, uint16_t p3, int16_t prio);
+
+/* Schedule a set of items starting from 'frame_offset' TDMA frames in the future */
+int tdma_schedule_set(uint8_t frame_offset, const struct tdma_sched_item *item_set, uint16_t p3);
+
+/* Scan current frame scheduled items for flags */
+uint16_t tdma_sched_flag_scan(void);
+
+/* Execute pre-scheduled events for current frame */
+int tdma_sched_execute(void);
+
+/* Advance TDMA scheduler to the next bucket */
+void tdma_sched_advance(void);
+
+/* reset the scheduler; erase all scheduled items */
+void tdma_sched_reset(void);
+
+/* debug function: print number of entries of all TDMA buckets */
+void tdma_sched_dump(void);
+
+
+extern int tdma_end_set(uint8_t p1, uint8_t p2, uint16_t p3);
+#define SCHED_ITEM(x, p, y, z) { .cb = x, .p1 = y, .p2 = z, .prio = p, .flags = 0 }
+#define SCHED_ITEM_DT(x, p, y, z) { .cb = x, .p1 = y, .p2 = z, .prio = p, \
+ .flags = TDMA_IFLG_TPU | TDMA_IFLG_DSP }
+#define SCHED_END_FRAME() { .cb = NULL, .p1 = 0, .p2 = 0 }
+#define SCHED_END_SET() { .cb = &tdma_end_set, .p1 = 0, .p2 = 0 }
+
+#endif /* _L1_TDMA_SCHED_H */
diff --git a/src/target/firmware/include/layer1/toa.h b/src/target/firmware/include/layer1/toa.h
new file mode 100644
index 00000000..dea9dd96
--- /dev/null
+++ b/src/target/firmware/include/layer1/toa.h
@@ -0,0 +1,10 @@
+#ifndef _L1_TOA_H
+#define _L1_TOA_H
+
+/* Input a qbits error sample into the TOA averaging */
+void toa_input(int32_t offset, uint32_t snr);
+
+/* Reset the TOA counters */
+void toa_reset(void);
+
+#endif
diff --git a/src/target/firmware/include/layer1/tpu_window.h b/src/target/firmware/include/layer1/tpu_window.h
new file mode 100644
index 00000000..7b146f12
--- /dev/null
+++ b/src/target/firmware/include/layer1/tpu_window.h
@@ -0,0 +1,24 @@
+#ifndef _L1_TPU_CTRL_H
+#define _L1_TPU_CTRL_H
+
+enum l1_rxwin_type {
+ L1_RXWIN_PW, /* power measurement */
+ L1_RXWIN_FB, /* FCCH burst detection */
+ L1_RXWIN_SB, /* SCH burst detection */
+ L1_RXWIN_NB, /* Normal burst decoding */
+ _NUM_L1_RXWIN
+};
+
+enum l1_txwin_type {
+ L1_TXWIN_NB, /* Normal burst sending */
+ L1_TXWIN_AB, /* RACH burst sending */
+ _NUM_L1_TXWIN
+};
+
+void l1s_win_init(void);
+void l1s_rx_win_ctrl(uint16_t arfcn, enum l1_rxwin_type wtype, uint8_t tn_ofs);
+void l1s_tx_win_ctrl(uint16_t arfcn, enum l1_txwin_type wtype, uint8_t pwr, uint8_t tn_ofs);
+
+void tpu_end_scenario(void);
+
+#endif /* _L1_TPU_CTRL_H */
diff --git a/src/target/firmware/include/manifest.h b/src/target/firmware/include/manifest.h
new file mode 100644
index 00000000..6c1b2026
--- /dev/null
+++ b/src/target/firmware/include/manifest.h
@@ -0,0 +1,10 @@
+
+#ifndef _MANIFEST_H
+#define _MANIFEST_H
+
+extern const char *manifest_application;
+extern const char *manifest_revision;
+extern const char *manifest_board;
+extern const char *manifest_environment;
+
+#endif /* !_MANIFEST_H */
diff --git a/src/target/firmware/include/memory.h b/src/target/firmware/include/memory.h
new file mode 100644
index 00000000..b0a0490c
--- /dev/null
+++ b/src/target/firmware/include/memory.h
@@ -0,0 +1,28 @@
+#ifndef _MEMORY_H
+#define _MEMORY_H
+
+#define __arch_getb(a) (*(volatile unsigned char *)(a))
+#define __arch_getw(a) (*(volatile unsigned short *)(a))
+#define __arch_getl(a) (*(volatile unsigned int *)(a))
+
+#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v))
+#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v))
+#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v))
+
+#define __raw_writeb(v,a) __arch_putb(v,a)
+#define __raw_writew(v,a) __arch_putw(v,a)
+#define __raw_writel(v,a) __arch_putl(v,a)
+
+#define __raw_readb(a) __arch_getb(a)
+#define __raw_readw(a) __arch_getw(a)
+#define __raw_readl(a) __arch_getl(a)
+
+#define writeb(v,a) __arch_putb(v,a)
+#define writew(v,a) __arch_putw(v,a)
+#define writel(v,a) __arch_putl(v,a)
+
+#define readb(a) __arch_getb(a)
+#define readw(a) __arch_getw(a)
+#define readl(a) __arch_getl(a)
+
+#endif /* _MEMORY_H */
diff --git a/src/target/firmware/include/mtk/bfe.h b/src/target/firmware/include/mtk/bfe.h
new file mode 100644
index 00000000..b07f620d
--- /dev/null
+++ b/src/target/firmware/include/mtk/bfe.h
@@ -0,0 +1,107 @@
+#ifndef _MTK_BFE_H
+#define _MTK_BFE_H
+
+/* MTK Baseband Frontend */
+
+/* MT6235 Chapter 10 */
+
+enum mtk_bfe_reg {
+ BFE_CON = 0x0000,
+ BFE_STA = 0x0004,
+ /* Rx Configuration Register */
+ RX_CFG = 0x0010,
+ /* Rx Control Register */
+ RX_CON = 0x0014,
+ /* RX Interference Detection Power Measurement Control Register */
+ RX_PM_CON = 0x0018,
+ /* RX FIR Coefficient Set ID Control Register */
+ RX_FIR_CSID_CON = 0x001c,
+ /* RX Ram0 Coefficient Set 0 Register */
+ RX_RAM0_CS0 = 0x0070,
+ /* RX Ram1 Coefficient Set 0 Register */
+ RX_RAM1_CS0 = 0x0020,
+ /* Rx Interference Detection HPF Power Register */
+ RX_HPWR_STS = 0x00b0,
+ /* Rx Interference Detection BPF Power Register */
+ RX_BPWR_STS = 0x00b4,
+
+ TX_CFG = 0x0060,
+ TX_CON = 0x0064,
+ TX_OFF = 0x0068,
+};
+
+#define RX_RAM0_CS(n) (RX_RAM0_CS0 + (n)*4)
+#define RX_RAM1_CS(n) (RX_RAM0_CS1 + (n)*4)
+
+/* SWAP I/Q before input to baesband frontend */
+#define RX_CFG_SWAP_IQ 0x0001
+/* Bypass RX FIR filter control */
+#define RX_CFG_BYPFLTR 0x0002
+/* Number of RX FIR filter taps */
+#define RX_CFG_FIRTPNO(n) (((n) & 0x3f) << 4)
+
+#define RX_CON_BLPEN_NORMAL (0 << 0)
+#define RX_CON_BLPEN_LOOPB (1 << 0)
+#define RX_CON_BLPEN_LOOPB_FILT (2 << 0)
+
+/* Phase de-rotation in wide FIR data path */
+#define RX_CON_PH_ROEN_W (1 << 2)
+/* Phase de-rotation in narrow FIR data path */
+#define RX_CON_PH_ROEN_N (1 << 3)
+/* RX I-data gain compenstation select (+/- 1.5dB */
+#define RX_CON_IGAINSEL_00dB (0 << 4)
+#define RX_CON_IGAINSEL_03dB (1 << 4)
+#define RX_CON_IGAINSEL_06dB (2 << 4)
+#define RX_CON_IGAINSEL_09dB (3 << 4)
+#define RX_CON_IGAINSEL_12dB (4 << 4)
+#define RX_CON_IGAINSEL_15dB (5 << 4)
+#define RX_CON_IGAINSEL_n03dB (9 << 4)
+#define RX_CON_IGAINSEL_n06dB (10 << 4)
+#define RX_CON_IGAINSEL_n09dB (11 << 4)
+#define RX_CON_IGAINSEL_n12dB (12 << 4)
+#define RX_CON_IGAINSEL_n15dB (13 << 4)
+
+/* TX_CFG */
+/* Appending Bits enable */
+#define TX_CFG_APNDEN (1 << 0)
+/* Ramp Profile Select for 8PSK */
+#define TX_CFG_RPSEL_I (0 << 1) /* 50 kHz sine tone */
+#define TX_CFG_RPSEL_II (1 << 1) /* null DC I/Q */
+#define TX_CFG_RPSEL_III (3 << 1)
+#define TX_CFG_INTEN (1 << 3) /* Interpolate between bursts */
+#define TX_CFG_MDBYP (1 << 4) /* Modulator Bypass */
+#define TX_CFG_SGEN (1 << 5) /* 540 kHz sine tone */
+#define TX_CFG_ALL_10GEN_ZERO (1 << 6)
+#define TX_CFG_ALL_10GEN_ONE (2 << 6)
+#define TX_CFG_SW_QBCNT(n) (((n) & 0x1f) << 8)
+#define TX_CFG_GMSK_DTAP_SYM_1 (0 << 13)
+#define TX_CFG_GMSK_DTAP_SYM_0 (1 << 13)
+#define TX_CFG_GMSK_DTAP_SYM_2 (2 << 13)
+
+#define TX_CON_IQSWP (1 << 0) /* Swap I/Q */
+/* GMSK or 8PSK modulation for 1st through 4th burst */
+#define TX_CON_MDSEL1_8PSK (1 << 2)
+#define TX_CON_MDSEL2_8PSK (1 << 3)
+#define TX_CON_MDSEL3_8PSK (1 << 4)
+#define TX_CON_MDSEL4_8PSK (1 << 5)
+/* Quadratur phase compensation select */
+#define TX_CON_PHSEL_0deg (0 << 8)
+#define TX_CON_PHSEL_1deg (1 << 8)
+#define TX_CON_PHSEL_2deg (2 << 8)
+#define TX_CON_PHSEL_3deg (3 << 8)
+#define TX_CON_PHSEL_4deg (4 << 8)
+#define TX_CON_PHSEL_5deg (5 << 8)
+#define TX_CON_PHSEL_n5deg (10 << 8)
+#define TX_CON_PHSEL_n4deg (11 << 8)
+#define TX_CON_PHSEL_n3deg (12 << 8)
+#define TX_CON_PHSEL_n2deg (13 << 8)
+#define TX_CON_PHSEL_n1deg (14 << 8)
+/* GMSK modulator output latenct */
+#define TX_CON_GMSK_DTAP_QB(n) (((n) & 3) << 12)
+
+#define TX_OFF_I(n) (((n) & 0x3f) << 0)
+#define TX_OFF_Q(n) (((n) & 0x3f) << 8)
+/* Double Buffering */
+#define TX_OFF_TYP_DB 0x8000
+
+#endif /* _MTK_BFE_H */
diff --git a/src/target/firmware/include/mtk/bpi.h b/src/target/firmware/include/mtk/bpi.h
new file mode 100644
index 00000000..8aa8ee54
--- /dev/null
+++ b/src/target/firmware/include/mtk/bpi.h
@@ -0,0 +1,20 @@
+#ifndef _MTK_BPI_H
+#define _MTK_BPI_H
+
+/* MTK Baseband Parallel Interface */
+
+/* Chapter 9.2 of MT6235 Data Sheet */
+
+#define BPI_BUF(n) (BPI_BUF0 + ((n) * 4))
+
+#define MTK_BPI(n) (n)
+
+enum mtk_bpi_reg {
+ BPI_CON = 0x0000,
+ BPI_BUF0 = 0x0004,
+ BPI_ENA0 = 0x00b0,
+ BPI_ENA1 = 0x00b4,
+ BPI_ENA2 = 0x00b8,
+};
+
+#endif /* _MTK_BPI_H */
diff --git a/src/target/firmware/include/mtk/bsi.h b/src/target/firmware/include/mtk/bsi.h
new file mode 100644
index 00000000..6f381ce3
--- /dev/null
+++ b/src/target/firmware/include/mtk/bsi.h
@@ -0,0 +1,41 @@
+#ifndef _MTK_BSI_H
+#define _MTK_BSI_H
+
+/* MTK Baseband Serial Interface */
+
+enum bsi_reg {
+ BSI_CON = 0x0000,
+ BSI_D0_CON = 0x0004,
+ BSI_D0_DAT = 0x0008,
+
+ BSI_ENA_0 = 0x0190,
+ BSI_ENA_1 = 0x0194,
+ BSI_IO_CON = 0x0198,
+ BSI_DOUT = 0x019c,
+ BSI_DIN = 0x01a0,
+ BSI_PAIR_NUM = 0x01a4,
+
+};
+
+/* Compute offset of BSI_D0_CON / BSI_D0_DAT registers */
+#define BSI_Dn_CON(x) (BSI_D0_CON + (x * 8))
+#define BSI_Dn_CON(x) (BSI_D0_DAT + (x * 8))
+
+/* MT6235 Section 9.1.1 */
+#define BSI_CON_CLK_POL_INV (1 << 0)
+#define BSI_CON_CLK_SPD_52_2 (0 << 1) /* 26 MHz */
+#define BSI_CON_CLK_SPD_52_4 (1 << 1) /* 13 MHz */
+#define BSI_CON_CLK_SPD_52_6 (2 << 1) /* 8.67 MHz */
+#define BSI_CON_CLK_SPD_52_8 (3 << 1) /* 6.50 MHz */
+#define BSI_CON_IMOD (1 << 3)
+#define BSI_CON_EN0_LEN_SHORT (1 << 4)
+#define BSI_CON_EN0_POL_INV (1 << 5)
+#define BSI_CON_EN0_LEN_SHORT (1 << 6)
+#define BSI_CON_EN0_POL_INV (1 << 7)
+#define BSI_CON_SETENV (1 << 8)
+
+/* how the length is encoded in BSI_Dx_CON */
+#define BSI_Dx_LEN(n) ((n & 0x7f) << 8)
+#define BSI_Dx_ISB 0x8000 /* select device 1 */
+
+#endif /* _MTK_BSI_H */
diff --git a/src/target/firmware/include/mtk/emi.h b/src/target/firmware/include/mtk/emi.h
new file mode 100644
index 00000000..18184992
--- /dev/null
+++ b/src/target/firmware/include/mtk/emi.h
@@ -0,0 +1,42 @@
+/*
+ * (C) 2010 by Tieto <www.tieto.com>
+ * Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __MTK_EMI_H_
+#define __MTK_EMI_H_
+
+/* External Memory Interface register definitions */
+#define MTK_EMI_CONA (MTK_EMI_BASE + 0x00)
+#define MTK_EMI_CONB (MTK_EMI_BASE + 0x08)
+#define MTK_EMI_CONC (MTK_EMI_BASE + 0x10)
+#define MTK_EMI_COND (MTK_EMI_BASE + 0x18)
+#define MTK_EMI_CONI (MTK_EMI_BASE + 0x40)
+#define MTK_EMI_CONJ (MTK_EMI_BASE + 0x48)
+#define MTK_EMI_CONK (MTK_EMI_BASE + 0x50)
+#define MTK_EMI_CONL (MTK_EMI_BASE + 0x58)
+#define MTK_EMI_CONM (MTK_EMI_BASE + 0x60)
+#define MTK_EMI_CONN (MTK_EMI_BASE + 0x68)
+#define MTK_EMI_GENA (MTK_EMI_BASE + 0x70)
+#define MTK_EMI_GENB (MTK_EMI_BASE + 0x78)
+#define MTK_EMI_GENC (MTK_EMI_BASE + 0x80)
+#define MTK_EMI_GEND (MTK_EMI_BASE + 0x88)
+
+#endif
diff --git a/src/target/firmware/include/mtk/mt6139.h b/src/target/firmware/include/mtk/mt6139.h
new file mode 100644
index 00000000..35458b5d
--- /dev/null
+++ b/src/target/firmware/include/mtk/mt6139.h
@@ -0,0 +1,60 @@
+#ifndef _MTK_MT6139_H
+#define _MTK_MT6139_H
+
+enum mt6139_band {
+ MTRF_BAND_GSM850 = 0,
+ MTRF_BAND_GSM900 = 1,
+ MTRF_BAND_GSM1800 = 2,
+ MTRF_BAND_GSM1900 = 3,
+};
+
+#define MT6139_CW0_SYNCP_SHIFT 0
+#define MT6139_CW0_SYNCPW (1 << 2)
+#define MT6139_CW0_DIEN (1 << 3)
+#define MT6139_CW0_FLT (1 << 4)
+#define MT6139_CW0_AFC_SHIFT 5
+#define MT6139_CW0_VCO_SEL (1 << 11)
+#define MT6139_CW0_GPO (1 << 12)
+#define MT6139_CW0_POR (1 << 13)
+
+#define MT6139_CW1_NFRACT_SHIFT 0
+#define MT6139_CW1_NINT_SHIFT 8
+#define MT6139_CW1_BAND_SHIFT 16
+#define MT6139_CW1_TRX_850 (1 << 18)
+
+#define MT6139_CW2_GAINTBL_SHIFT 0
+#define MT6139_CW2_MODE_SHIFT 6
+#define MT6139_CW2_AUTO_CAL (1 << 9)
+#define MT6139_CW2_DCD_AQ_SHIFT 10
+#define MT6139_CW2_DCD_AI_SHIFT 16
+
+#define MT6139_CW9_DCD_CQ_SHIFT 0
+#define MT6139_CW9_DCD_BQ_SHIFT 7
+#define MT6139_CW9_PWR_DAC_C (1 << 14)
+#define MT6139_CW9_PWR_DAC_B (1 << 15)
+#define MT6139_CW9_PWR_DAC_A (1 << 16)
+#define MT6139_CW9_AM_ENABLE (1 << 17)
+
+enum mt6139_cw2_mode {
+ MODE_SLEEP = 0x0,
+ MODE_WARM_UP = 0x1,
+ MODE_RECEIVE = 0x3,
+ MODE_TRANSMIT = 0x4,
+};
+
+#define MT6139_CW11_TX_CTL (1 << 0)
+#define MT6139_CW11_TXG_IQM (1 << 1)
+#define MT6139_CW11_TXD_IQM (1 << 2)
+#define MT6139_CW11_TX_DIV2 (1 << 3)
+#define MT6139_CW11_TX_DIV4 (1 << 4)
+#define MT6139_CW11_TXG_BUF (1 << 5)
+#define MT6139_CW11_TXD_BUF (1 << 6)
+#define MT6139_CW11_TXMODGAIN_SHIFT 7
+#define MT6139_CW11_TX_FLT_SHIFT 10
+#define MT6139_CW11_TXAPC_SHIFT 14
+#define MT6139_CW11_TXPW_SHIFT 16
+#define MT6139_CW11_TXBIAST_SHIFT 18
+#define MT6139_CW11_TXDIV_GC0 (1 << 20)
+#define MT6139_CW11_TXDIV_GC1 (1 << 21)
+
+#endif /* _MTK_MT6139_H */
diff --git a/src/target/firmware/include/mtk/mt6235.h b/src/target/firmware/include/mtk/mt6235.h
new file mode 100644
index 00000000..fb9d368e
--- /dev/null
+++ b/src/target/firmware/include/mtk/mt6235.h
@@ -0,0 +1,74 @@
+/*
+ * (C) 2010 by Tieto <www.tieto.com>
+ * Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __MT6235_H
+#define __MT6235_H
+
+/* Peripheral base addresses */
+#define MTK_EFUSE_BASE 0x80000000
+#define MTK_CONFG_BASE 0x80010000
+#define MTK_GPIO_BASE 0x80020000
+#define MTK_RGU_BASE 0x80030000
+#define MTK_EMI_BASE 0x81000000
+#define MTK_CIRQ_BASE 0x81010000
+#define MTK_DMA_BASE 0x81020000
+#define MTK_UART1_BASE 0x81030000
+#define MTK_UART2_BASE 0x81040000
+#define MTK_UART3_BASE 0x81050000
+#define MTK_GPT_BASE 0x81060000
+#define MTK_KP_BASE 0x81080000
+#define MTK_PWM_BASE 0x81090000
+#define MTK_SIM_BASE 0x810A0000
+#define MTK_RTC_BASE 0x810C0000
+#define MTK_SEJ_BASE 0x810D0000
+#define MTK_BM_BASE 0x810E0000
+#define MTK_IRDA_BASE 0x810F0000
+#define MTK_I2C_BASE 0x81100000
+#define MTK_MSDC_BASE 0x81110000
+#define MTK_NFI_BASE 0x81120000
+#define MTK_MSSDC2_BASE 0x81140000
+#define MTK_TDMA_BASE 0x82000000
+#define MTK_BSI_BASE 0x82010000
+#define MTK_BPI_BASE 0x82020000
+#define MTK_AFC_BASE 0x82030000
+#define MTK_APC_BASE 0x82040000
+#define MTK_AUXADC_BASE 0x82050000
+#define MTK_DIVIDER_BASE 0x82060000
+#define MTK_FSC_BASE 0x82070000
+#define MTK_GCU_BASE 0x82080000
+#define MTK_CSD_ACC_BASE 0x82090000
+#define MTK_SHARE1_BASE 0x820A0000
+#define MTK_IRDBG1_BASE 0x820B0000
+#define MTK_SHARE2_BASE 0x820C0000
+#define MTK_IRDBG2_BASE 0x820D0000
+#define MTK_PATCH_BASE 0x820E0000
+#define MTK_AFE_BASE 0x820F0000
+#define MTK_BFE_BASE 0x82100000
+#define MTK_PLL_BASE 0x83000000
+#define MTK_ACIF_BASE 0x83010000
+#define MTK_GMC_BASE 0x84000000
+#define MTK_G2D_BASE 0x84010000
+#define MTK_GCMQ_BASE 0x84020000
+#define MTK_CAM_BASE 0x840B0000
+#define MTK_CRZ_BASE 0x840E0000
+
+#endif
diff --git a/src/target/firmware/include/mtk/mt6235_sciphone_g2.h b/src/target/firmware/include/mtk/mt6235_sciphone_g2.h
new file mode 100644
index 00000000..74d9e7b8
--- /dev/null
+++ b/src/target/firmware/include/mtk/mt6235_sciphone_g2.h
@@ -0,0 +1,38 @@
+#ifndef _SCIPHONE_G2_H
+#define _SCIPHONE_G2_H
+/* Bluelans Sciphone G2 support */
+
+/* Use of the Baseband Parallel Interface by the G2 board */
+#define HB_TX MTK_BPI(0)
+#define PCS_RX MTK_BPI(1)
+#define LB_TX MTK_BPI(2)
+#define PA_EN MTK_BPI(4)
+#define BAND_SW MTK_BPI(5)
+#define MODE_PA MTK_BPI(7)
+#define RF_VCO_EN MTK_BPI(9)
+
+#define GPIO_GPS_PWR_EN MTK_GPIO(19)
+#define GPIO_WIFI_EN MTK_GPIO(20)
+#define GPIO_OP1_EN MTK_GPIO(22)
+#define GPIO_BT_PWR_EN MTK_GPIO(39)
+#define GPIO_BT_RST MTK_GPIO(62)
+#define GPIO_USB_CHR_ID MTK_GPIO(73)
+#define GPIO_FM_SCL MTK_GPIO(46)
+#define GPIO_FM_SDA MTK_GPIO(47)
+#define GPIO_GS_SCL MTK_GPIO(48)
+#define GPIO_GS_SDA MTK_GPIO(58)
+#define GPIO_GS_EN MTK_GPIO(26)
+
+#define GPIO_GPS_EINT MTK_GPIO(42)
+
+#define EINT_HEADSET MTK_EINT(0)
+#define EINT_BT MTK_EINT(1)
+#define EINT_GPS2GSM MTK_EINT(2)
+#define EINT_WIFI MTK_EINT(3)
+
+#define CLKM_BT_32k MTK_CLKM(2)
+#define CLKM_WIFI_32k MTK_CLKM(3)
+#define CLKM_FM_32k MTK_CLKM(4)
+
+
+#endif /* _SCIPHONE_G2_H */
diff --git a/src/target/firmware/include/mtk/system.h b/src/target/firmware/include/mtk/system.h
new file mode 100644
index 00000000..45430291
--- /dev/null
+++ b/src/target/firmware/include/mtk/system.h
@@ -0,0 +1,195 @@
+/*
+ * (C) 2010 by Tieto <www.tieto.com>
+ * Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __MTK_SYSTEM_H_
+#define __MTK_SYSTEM_H_
+
+/*
+ * Configuration block section (Clock, Power Down, Version and Reset
+ */
+
+/* Register definitions */
+#define MTK_CONFG_HW_VERSION (MTK_CONFG_BASE + 0x000)
+#define MTK_CONFG_FW_VERSION (MTK_CONFG_BASE + 0x004)
+#define MTK_CONFG_HW_CODE (MTK_CONFG_BASE + 0x008)
+#define MTK_CONFG_SLEEP_CON (MTK_CONFG_BASE + 0x114)
+#define MTK_CONFG_MCUCLK_CON (MTK_CONFG_BASE + 0x118)
+#define MTK_CONFG_DSPCLK_CON (MTK_CONFG_BASE + 0x11C)
+#define MTK_CONFG_IDN_SEL (MTK_CONFG_BASE + 0x200)
+#define MTK_CONFG_PDN_CON0 (MTK_CONFG_BASE + 0x300)
+#define MTK_CONFG_PDN_CON1 (MTK_CONFG_BASE + 0x304)
+#define MTK_CONFG_PDN_CON2 (MTK_CONFG_BASE + 0x308)
+#define MTK_CONFG_PDN_CON3 (MTK_CONFG_BASE + 0x30C)
+#define MTK_CONFG_PDN_SET0 (MTK_CONFG_BASE + 0x310)
+#define MTK_CONFG_PDN_SET1 (MTK_CONFG_BASE + 0x314)
+#define MTK_CONFG_PDN_SET2 (MTK_CONFG_BASE + 0x318)
+#define MTK_CONFG_PDN_SET3 (MTK_CONFG_BASE + 0x31C)
+#define MTK_CONFG_PDN_CLR0 (MTK_CONFG_BASE + 0x320)
+#define MTK_CONFG_PDN_CLR1 (MTK_CONFG_BASE + 0x324)
+#define MTK_CONFG_PDN_CLR2 (MTK_CONFG_BASE + 0x328)
+#define MTK_CONFG_PDN_CLR3 (MTK_CONFG_BASE + 0x32C)
+
+/* CONFG_MCUCLK_CON bit fields definitions */
+#define MCUCLK_CON_AHBX8CLK_SHIFT (0)
+#define MCUCLK_CON_AHBX4CLK_SHIFT (4)
+#define MCUCLK_CON_ARMCLK_SHIFT (8)
+#define MCUCLK_CON_EMICLK_SHIFT (12)
+
+/* PDN_CON0 bit fields definitions */
+#define PDN_CON0_CON0_DMA (1 << 0)
+#define PDN_CON0_USB (1 << 1)
+#define PDN_CON0_GCU (1 << 2)
+#define PDN_CON0_WAVE (1 << 3)
+#define PDN_CON0_SEJ (1 << 4)
+#define PDN_CON0_IR (1 << 6)
+#define PDN_CON0_PWM3 (1 << 7)
+#define PDN_CON0_PWM (1 << 8)
+#define PDN_CON0_SIM2 (1 << 10)
+#define PDN_CON0_IRDBG1 (1 << 12)
+#define PDN_CON0_IRDBG2 (1 << 13)
+
+/* PDN_CON1 bit fields definitions */
+#define PDN_CON1_GPT (1 << 0)
+#define PDN_CON1_KP (1 << 1)
+#define PDN_CON1_GPIO (1 << 2)
+#define PDN_CON1_UART1 (1 << 3)
+#define PDN_CON1_SIM (1 << 4)
+#define PDN_CON1_PWM1 (1 << 5)
+#define PDN_CON1_LCD (1 << 7)
+#define PDN_CON1_UART2 (1 << 8)
+#define PDN_CON1_MSDC (1 << 9)
+#define PDN_CON1_TP (1 << 10)
+#define PDN_CON1_PWM2 (1 << 11)
+#define PDN_CON1_NFI (1 << 12)
+#define PDN_CON1_UART3 (1 << 14)
+#define PDN_CON1_IRDA (1 << 15)
+
+/* PDN_CON2 bit fields definitions */
+#define PDN_CON2_TDMA (1 << 0)
+#define PDN_CON2_RTC (1 << 1)
+#define PDN_CON2_BSI (1 << 2)
+#define PDN_CON2_BPI (1 << 3)
+#define PDN_CON2_AFC (1 << 4)
+#define PDN_CON2_APC (1 << 5)
+
+/*
+ * Reset Generation Unit block section
+ */
+#define MTK_RGU_WDT_MODE (MTK_RGU_BASE + 0x00)
+#define MTK_RGU_WDT_LENGTH (MTK_RGU_BASE + 0x04)
+#define MTK_RGU_WDT_RESTART (MTK_RGU_BASE + 0x08)
+#define MTK_RGU_WDT_STA (MTK_RGU_BASE + 0x0C)
+#define MTK_RGU_SW_PERIPH_RSTN (MTK_RGU_BASE + 0x10)
+#define MTK_RGU_SW_DSP_RSTN (MTK_RGU_BASE + 0x14)
+#define MTK_RGU_WDT_RSTINTERVAL (MTK_RGU_BASE + 0x18)
+#define MTK_RGU_WDT_SWRST (MTK_RGU_BASE + 0x1C)
+
+#define WDT_MODE_KEY 0x2200
+#define WDT_LENGTH_KEY 0x0008
+#define WDT_RESTART_KEY 0x1971
+#define SW_PERIPH_RSTN_KEY 0x0037
+#define WDT_SWRST_KEY 0x1209
+
+/*
+ * RTC block section
+ */
+
+/* RTC registers definition */
+#define MTK_RTC_BBPU (MTK_RTC_BASE + 0x00)
+#define MTK_RTC_IRQ_STA (MTK_RTC_BASE + 0x04)
+#define MTK_RTC_IRQ_EN (MTK_RTC_BASE + 0x08)
+#define MTK_RTC_CII_EN (MTK_RTC_BASE + 0x0C)
+#define MTK_RTC_AL_MASK (MTK_RTC_BASE + 0x10)
+#define MTK_RTC_TC_SEC (MTK_RTC_BASE + 0x14)
+#define MTK_RTC_TC_MIN (MTK_RTC_BASE + 0x18)
+#define MTK_RTC_TC_HOU (MTK_RTC_BASE + 0x1C)
+#define MTK_RTC_TC_DOM (MTK_RTC_BASE + 0x20)
+#define MTK_RTC_TC_DOW (MTK_RTC_BASE + 0x24)
+#define MTK_RTC_TC_MTH (MTK_RTC_BASE + 0x28)
+#define MTK_RTC_TC_YEA (MTK_RTC_BASE + 0x2C)
+#define MTK_RTC_AL_SEC (MTK_RTC_BASE + 0x30)
+#define MTK_RTC_AL_MIN (MTK_RTC_BASE + 0x34)
+#define MTK_RTC_AL_HOU (MTK_RTC_BASE + 0x38)
+#define MTK_RTC_AL_DOM (MTK_RTC_BASE + 0x3C)
+#define MTK_RTC_AL_DOW (MTK_RTC_BASE + 0x40)
+#define MTK_RTC_AL_MTH (MTK_RTC_BASE + 0x44)
+#define MTK_RTC_AL_YEA (MTK_RTC_BASE + 0x48)
+#define MTK_RTC_XOSCCALI (MTK_RTC_BASE + 0x4C)
+#define MTK_RTC_POWERKEY1 (MTK_RTC_BASE + 0x50)
+#define MTK_RTC_POWERKEY2 (MTK_RTC_BASE + 0x54)
+#define MTK_RTC_PDN1 (MTK_RTC_BASE + 0x58)
+#define MTK_RTC_PDN2 (MTK_RTC_BASE + 0x5C)
+#define MTK_RTC_SPAR1 (MTK_RTC_BASE + 0x64)
+#define MTK_RTC_DIFF (MTK_RTC_BASE + 0x6C)
+#define MTK_RTC_CALI (MTK_RTC_BASE + 0x70)
+#define MTK_RTC_WRTGR (MTK_RTC_BASE + 0x74)
+
+#define POWERKEY1_MAGIC 0xA357
+#define POWERKEY2_MAGIC 0x67D2
+
+/* RTC_BBPU bit fields definitions */
+#define RTC_BBPU_PWREN (1 << 0)
+#define RTC_BBPU_WRITE_EN (1 << 1)
+#define RTC_BBPU_BBPU (1 << 2)
+#define RTC_BBPU_AUTO (1 << 3)
+#define RTC_BBPU_CLRPKY (1 << 4)
+#define RTC_BBPU_RELOAD (1 << 5)
+#define RTC_BBPU_CBUSY (1 << 6)
+#define RTC_BBPU_DBING (1 << 7)
+#define RTC_BBPU_KEY_BBPU (1 << 8)
+
+/* RTC_BBPU write is only acceptable when KEY_BBPU=0x43 */
+#define BBPU_MAGIC 0x4300
+
+/*
+ * PLL block section
+ */
+
+/* PLL registers definition */
+#define MTK_PLL_PLL (MTK_PLL_BASE + 0x00)
+#define MTK_PLL_PLL2 (MTK_PLL_BASE + 0x04)
+#define MTK_PLL_CLK_CON (MTK_PLL_BASE + 0x18)
+#define MTK_PLL_PDN_CON (MTK_PLL_BASE + 0x1C)
+
+/* MTK_PLL_PLL bit fields definitions */
+#define PLL_PLLVCOSEL (0 << 0)
+#define PLL_MPLLSEL_SYSCLK (1 << 3)
+#define PLL_MPLLSEL_PLL (2 << 3)
+#define PLL_DPLLSEL (1 << 5)
+#define PLL_UPLLSEL (1 << 6)
+#define PLL_RST (1 << 7)
+#define PLL_CALI (1 << 8)
+
+/* MTK_PLL_CLK_CON bit fields definitions */
+#define PLL_CLKSQ_DIV2_DSP (1 << 0)
+#define PLL_CLKSQ_DIV2_MCU (1 << 1)
+#define PLL_CLKSQ_PLD (1 << 2)
+#define PLL_SRCCLK (1 << 7)
+#define PLL_CLKSQ_TEST (1 << 15)
+
+/* MTK_PLL_PDN_CON bit fields definitions */
+#define PLL_PDN_CON_CLKSQ (1 << 11)
+#define PLL_PDN_CON_MCU_DIV2 (1 << 12)
+#define PLL_PDN_CON_PLL (1 << 13)
+#define PLL_PDN_CON_DSP_DIV2 (1 << 15)
+
+#endif
diff --git a/src/target/firmware/include/mtk/tdma_timer.h b/src/target/firmware/include/mtk/tdma_timer.h
new file mode 100644
index 00000000..dec0a8a4
--- /dev/null
+++ b/src/target/firmware/include/mtk/tdma_timer.h
@@ -0,0 +1,60 @@
+#ifndef _MTK_TDMA_H
+#define _MTK_TDMA_H
+
+/* MTK TDMA Timer */
+
+/* MT6235 Section 11 */
+
+enum mtk_tdma_reg {
+ /* Read current quarter bit count */
+ TDMA_TQCNT = 0x0000,
+ /* Latched Qbit counter reset position */
+ TDMA_WRAP = 0x0004,
+ /* Direct Qbit counter reset position */
+ TDMA_WRAPIMD = 0x0008,
+ /* Event latch position */
+ TDMA_EVTVAL = 0x000c,
+ /* DSP software control */
+ TDMA_DTIRQ = 0x0010,
+ /* MCU software control */
+ TDMA_CTIRQ1 = 0x0014,
+ TDMA_CTIRQ2 = 0x0018,
+ /* AFC control */
+ TDMA_AFC0 = 0x0020,
+ TDMA_AFC1 = 0x0024,
+ TDMA_AFC2 = 0x0028,
+ TDMA_AFC3 = 0x002c,
+
+ /* BSI event */
+ TDMA_BSI0 = 0x00b0,
+ /* BPI event */
+ TDMA_BPI0 = 0x0100,
+ /* Auxiliary ADC event */
+ TDMA_AUXEV0 = 0x0400,
+ TDMA_AUXEV1 = 0x0404,
+ /* Event Control */
+ TDMA_EVTENA0 = 0x0150,
+ TDMA_EVTENA1 = 0x0154,
+ TDMA_EVTENA2 = 0x0158,
+ TDMA_EVTENA3 = 0x015c,
+ TDMA_EVTENA4 = 0x0160,
+ TDMA_EVTENA5 = 0x0164,
+ TDMA_EVTENA6 = 0x0168,
+ TDMA_EVTENA6 = 0x016c,
+ TDMA_WRAPOFS = 0x0170,
+ TDMA_REGBIAS = 0x0174,
+ TDMA_DTXCON = 0x0180,
+ TDMA_RXCON = 0x0184,
+ TDMA_BDLCON = 0x0188,
+ TDMA_BULCON1 = 0x018c,
+ TDMA_BULCON2 = 0x0190,
+ TDMA_FB_FLAG = 0x0194,
+ TDMA_FB_CLRI = 0x0198,
+};
+
+#define TDMA_BSI(n) (TDMA_BSI0 + (n)*4)
+#define TDMA_BPI(n) (TDMA_BPI0 + (n)*4)
+
+
+
+#endif /* _MTK_TDMA_H */
diff --git a/src/target/firmware/include/rf/trf6151.h b/src/target/firmware/include/rf/trf6151.h
new file mode 100644
index 00000000..c1eaf3b2
--- /dev/null
+++ b/src/target/firmware/include/rf/trf6151.h
@@ -0,0 +1,51 @@
+#ifndef _TRF6151_H
+#define _TRF6151_H
+
+#include <osmocom/gsm/gsm_utils.h>
+
+/* initialize (reset + power up) */
+void trf6151_init(uint8_t tsp_uid, uint16_t tsp_reset_id);
+
+/* switch power off or on */
+void trf6151_power(int on);
+
+/* obtain the current total gain of the TRF6151 */
+uint8_t trf6151_get_gain_reg(void);
+
+/* put current set (or computed) gain to register */
+int trf6151_set_gain_reg(uint8_t dbm, int high);
+
+/* set the global gain to use */
+int trf6151_set_gain(uint8_t dbm);
+
+/* obtain the global gain set */
+uint8_t trf6151_get_gain(void);
+
+/* Request the PLL to be tuned to the given frequency */
+/* arfcn must have ARFCN_UPLINK flag set if you want uplink ! */
+/* tx selects the TX path only and doesn't set UL band ! */
+void trf6151_set_arfcn(uint16_t arfcn, int tx);
+
+enum trf6151_mode {
+ TRF6151_IDLE,
+ TRF6151_RX,
+ TRF6151_TX,
+};
+
+/* Set the operational mode of the TRF6151 chip */
+void trf6151_set_mode(enum trf6151_mode mode);
+
+void trf6151_test(uint16_t arfcn);
+void trf6151_tx_test(uint16_t arfcn);
+
+/* prepare a Rx window with the TRF6151 finished at time 'start' (in qbits) */
+void trf6151_rx_window(int16_t start_qbits, uint16_t arfcn);
+
+/* prepare a Tx window with the TRF6151 finished at time 'start' (in qbits) */
+void trf6151_tx_window(int16_t start_qbits, uint16_t arfcn);
+
+/* Given the expected input level of exp_inp dBm and the target of target_bb
+ * dBm, configure the RF Frontend with the respective gain */
+void trf6151_compute_gain(int16_t exp_inp, int16_t target_bb);
+
+#endif /* TRF6151_H */
diff --git a/src/target/firmware/include/rffe.h b/src/target/firmware/include/rffe.h
new file mode 100644
index 00000000..63a3a4b5
--- /dev/null
+++ b/src/target/firmware/include/rffe.h
@@ -0,0 +1,35 @@
+#ifndef _RFFE_H
+#define _RFFE_H
+
+#include <osmocom/gsm/gsm_utils.h>
+
+extern const uint8_t system_inherent_gain;
+
+/* initialize RF Frontend */
+void rffe_init(void);
+
+/* switch RF Frontend Mode */
+void rffe_mode(enum gsm_band band, int tx);
+
+/* query RF wiring */
+enum rffe_port
+{
+ PORT_LO = 0, /* Combined 850/900 port */
+ PORT_HI = 1, /* Combined 1800/1900 port */
+ PORT_GSM850 = 2,
+ PORT_GSM900 = 3,
+ PORT_DCS1800 = 4,
+ PORT_PCS1900 = 5,
+};
+
+uint32_t rffe_get_rx_ports(void);
+uint32_t rffe_get_tx_ports(void);
+
+/* get current gain of RF frontend (anything between antenna and baseband in dBm */
+uint8_t rffe_get_gain(void);
+
+void rffe_set_gain(uint8_t dbm);
+
+void rffe_compute_gain(int16_t exp_inp, int16_t target_bb);
+
+#endif
diff --git a/src/target/firmware/include/spi.h b/src/target/firmware/include/spi.h
new file mode 100644
index 00000000..0925a9a3
--- /dev/null
+++ b/src/target/firmware/include/spi.h
@@ -0,0 +1,7 @@
+#ifndef _SPI_H
+#define _SPI_H
+
+void spi_init(void);
+int spi_xfer(uint8_t dev_idx, uint8_t bitlen, const void *dout, void *din);
+
+#endif /* _SPI_H */
diff --git a/src/target/firmware/include/stdint.h b/src/target/firmware/include/stdint.h
new file mode 100644
index 00000000..627403f9
--- /dev/null
+++ b/src/target/firmware/include/stdint.h
@@ -0,0 +1,36 @@
+#ifndef OSMO_STDINT_H
+#define OSMO_STDINT_H
+
+/* some older toolchains (like gnuarm-3.x) don't provide a C99
+ compliant stdint.h yet, so we define our own here */
+
+/* to make matters worse newer gcc with glibc headers have
+ a incompatible definition of these types. We will use the
+ gcc'ism of #include_next to include the compiler's libc
+ header file and then check if it has defined int8_t and
+ if not we will use our own typedefs */
+
+/* another bad criteria. We can not detect __NEWLIB_H__ or
+ _NEWLIB_VERSION. Assume that older GCCs have a older C library
+ that did not include a stdint.h yet. This is for gnuarm-3.x
+ one of the compilers producing working code right now. */
+
+#if __GNUC__ > 3
+#include_next <stdint.h>
+#endif
+
+#ifndef __int8_t_defined
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#endif
+
+#endif
diff --git a/src/target/firmware/include/stdio.h b/src/target/firmware/include/stdio.h
new file mode 100644
index 00000000..15ed6688
--- /dev/null
+++ b/src/target/firmware/include/stdio.h
@@ -0,0 +1,52 @@
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+#include <sys/types.h>
+
+int printf(const char *format, ...);
+int sprintf(char *str, const char *format, ...);
+int snprintf(char *str, size_t size, const char *format, ...);
+
+#include <stdarg.h>
+
+int vprintf(const char *format, va_list ap);
+int vsprintf(char *str, const char *format, va_list ap);
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+int puts(const char *s);
+
+#if 0
+/* start.S based uart console */
+#include <calypso/uart.h>
+#define putchar(c) uart_putchar_wait(1, c)
+int puts(const char *s);
+#endif
+
+#if 0
+/* regular UART console */
+#include <console.h>
+#define putchar(c) cons_putchar(c)
+#define _puts(s) cons_puts(s)
+#define ARCH_HAS_CONSOLE
+#endif
+
+#if 1
+/* sercomm based console */
+#include <comm/sercomm_cons.h>
+#define putchar(c) sercomm_putchar(c)
+#define _puts(s) sercomm_puts(s)
+#define ARCH_HAS_CONSOLE
+#endif
+
+struct __file {
+};
+
+typedef struct __file FILE;
+
+/* non-standard */
+extern void phex(unsigned int c, unsigned int len);
+
+#endif /* _STDIO_H */
diff --git a/src/target/firmware/include/string.h b/src/target/firmware/include/string.h
new file mode 100644
index 00000000..f060659a
--- /dev/null
+++ b/src/target/firmware/include/string.h
@@ -0,0 +1,12 @@
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <sys/types.h>
+
+size_t strnlen(const char *s, size_t count);
+size_t strlen(const char *s);
+
+void *memset(void *s, int c, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+
+#endif
diff --git a/src/target/firmware/include/swab.h b/src/target/firmware/include/swab.h
new file mode 100644
index 00000000..61be900d
--- /dev/null
+++ b/src/target/firmware/include/swab.h
@@ -0,0 +1,297 @@
+#ifndef _LINUX_SWAB_H
+#define _LINUX_SWAB_H
+
+#include <stdint.h>
+#include <defines.h>
+#include <asm/swab.h>
+
+/*
+ * casts are necessary for constants, because we never know how for sure
+ * how U/UL/ULL map to uint16_t, uint32_t, uint64_t. At least not in a portable way.
+ */
+#define ___constant_swab16(x) ((uint16_t)( \
+ (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
+ (((uint16_t)(x) & (uint16_t)0xff00U) >> 8)))
+
+#define ___constant_swab32(x) ((uint32_t)( \
+ (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
+
+#define ___constant_swab64(x) ((uint64_t)( \
+ (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
+ (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
+ (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
+ (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
+ (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
+ (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
+ (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
+ (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56)))
+
+#define ___constant_swahw32(x) ((uint32_t)( \
+ (((uint32_t)(x) & (uint32_t)0x0000ffffUL) << 16) | \
+ (((uint32_t)(x) & (uint32_t)0xffff0000UL) >> 16)))
+
+#define ___constant_swahb32(x) ((uint32_t)( \
+ (((uint32_t)(x) & (uint32_t)0x00ff00ffUL) << 8) | \
+ (((uint32_t)(x) & (uint32_t)0xff00ff00UL) >> 8)))
+
+/*
+ * Implement the following as inlines, but define the interface using
+ * macros to allow constant folding when possible:
+ * ___swab16, ___swab32, ___swab64, ___swahw32, ___swahb32
+ */
+
+static inline __attribute_const__ uint16_t __fswab16(uint16_t val)
+{
+#ifdef __arch_swab16
+ return __arch_swab16(val);
+#else
+ return ___constant_swab16(val);
+#endif
+}
+
+static inline __attribute_const__ uint32_t __fswab32(uint32_t val)
+{
+#ifdef __arch_swab32
+ return __arch_swab32(val);
+#else
+ return ___constant_swab32(val);
+#endif
+}
+
+static inline __attribute_const__ uint64_t __fswab64(uint64_t val)
+{
+#ifdef __arch_swab64
+ return __arch_swab64(val);
+#elif defined(__SWAB_64_THRU_32__)
+ uint32_t h = val >> 32;
+ uint32_t l = val & ((1ULL << 32) - 1);
+ return (((uint64_t)__fswab32(l)) << 32) | ((uint64_t)(__fswab32(h)));
+#else
+ return ___constant_swab64(val);
+#endif
+}
+
+static inline __attribute_const__ uint32_t __fswahw32(uint32_t val)
+{
+#ifdef __arch_swahw32
+ return __arch_swahw32(val);
+#else
+ return ___constant_swahw32(val);
+#endif
+}
+
+static inline __attribute_const__ uint32_t __fswahb32(uint32_t val)
+{
+#ifdef __arch_swahb32
+ return __arch_swahb32(val);
+#else
+ return ___constant_swahb32(val);
+#endif
+}
+
+/**
+ * __swab16 - return a byteswapped 16-bit value
+ * @x: value to byteswap
+ */
+#define __swab16(x) \
+ (__builtin_constant_p((uint16_t)(x)) ? \
+ ___constant_swab16(x) : \
+ __fswab16(x))
+
+/**
+ * __swab32 - return a byteswapped 32-bit value
+ * @x: value to byteswap
+ */
+#define __swab32(x) \
+ (__builtin_constant_p((uint32_t)(x)) ? \
+ ___constant_swab32(x) : \
+ __fswab32(x))
+
+/**
+ * __swab64 - return a byteswapped 64-bit value
+ * @x: value to byteswap
+ */
+#define __swab64(x) \
+ (__builtin_constant_p((uint64_t)(x)) ? \
+ ___constant_swab64(x) : \
+ __fswab64(x))
+
+/**
+ * __swahw32 - return a word-swapped 32-bit value
+ * @x: value to wordswap
+ *
+ * __swahw32(0x12340000) is 0x00001234
+ */
+#define __swahw32(x) \
+ (__builtin_constant_p((uint32_t)(x)) ? \
+ ___constant_swahw32(x) : \
+ __fswahw32(x))
+
+/**
+ * __swahb32 - return a high and low byte-swapped 32-bit value
+ * @x: value to byteswap
+ *
+ * __swahb32(0x12345678) is 0x34127856
+ */
+#define __swahb32(x) \
+ (__builtin_constant_p((uint32_t)(x)) ? \
+ ___constant_swahb32(x) : \
+ __fswahb32(x))
+
+/**
+ * __swab16p - return a byteswapped 16-bit value from a pointer
+ * @p: pointer to a naturally-aligned 16-bit value
+ */
+static inline uint16_t __swab16p(const uint16_t *p)
+{
+#ifdef __arch_swab16p
+ return __arch_swab16p(p);
+#else
+ return __swab16(*p);
+#endif
+}
+
+/**
+ * __swab32p - return a byteswapped 32-bit value from a pointer
+ * @p: pointer to a naturally-aligned 32-bit value
+ */
+static inline uint32_t __swab32p(const uint32_t *p)
+{
+#ifdef __arch_swab32p
+ return __arch_swab32p(p);
+#else
+ return __swab32(*p);
+#endif
+}
+
+/**
+ * __swab64p - return a byteswapped 64-bit value from a pointer
+ * @p: pointer to a naturally-aligned 64-bit value
+ */
+static inline uint64_t __swab64p(const uint64_t *p)
+{
+#ifdef __arch_swab64p
+ return __arch_swab64p(p);
+#else
+ return __swab64(*p);
+#endif
+}
+
+/**
+ * __swahw32p - return a wordswapped 32-bit value from a pointer
+ * @p: pointer to a naturally-aligned 32-bit value
+ *
+ * See __swahw32() for details of wordswapping.
+ */
+static inline uint32_t __swahw32p(const uint32_t *p)
+{
+#ifdef __arch_swahw32p
+ return __arch_swahw32p(p);
+#else
+ return __swahw32(*p);
+#endif
+}
+
+/**
+ * __swahb32p - return a high and low byteswapped 32-bit value from a pointer
+ * @p: pointer to a naturally-aligned 32-bit value
+ *
+ * See __swahb32() for details of high/low byteswapping.
+ */
+static inline uint32_t __swahb32p(const uint32_t *p)
+{
+#ifdef __arch_swahb32p
+ return __arch_swahb32p(p);
+#else
+ return __swahb32(*p);
+#endif
+}
+
+/**
+ * __swab16s - byteswap a 16-bit value in-place
+ * @p: pointer to a naturally-aligned 16-bit value
+ */
+static inline void __swab16s(uint16_t *p)
+{
+#ifdef __arch_swab16s
+ __arch_swab16s(p);
+#else
+ *p = __swab16p(p);
+#endif
+}
+/**
+ * __swab32s - byteswap a 32-bit value in-place
+ * @p: pointer to a naturally-aligned 32-bit value
+ */
+static inline void __swab32s(uint32_t *p)
+{
+#ifdef __arch_swab32s
+ __arch_swab32s(p);
+#else
+ *p = __swab32p(p);
+#endif
+}
+
+/**
+ * __swab64s - byteswap a 64-bit value in-place
+ * @p: pointer to a naturally-aligned 64-bit value
+ */
+static inline void __swab64s(uint64_t *p)
+{
+#ifdef __arch_swab64s
+ __arch_swab64s(p);
+#else
+ *p = __swab64p(p);
+#endif
+}
+
+/**
+ * __swahw32s - wordswap a 32-bit value in-place
+ * @p: pointer to a naturally-aligned 32-bit value
+ *
+ * See __swahw32() for details of wordswapping
+ */
+static inline void __swahw32s(uint32_t *p)
+{
+#ifdef __arch_swahw32s
+ __arch_swahw32s(p);
+#else
+ *p = __swahw32p(p);
+#endif
+}
+
+/**
+ * __swahb32s - high and low byteswap a 32-bit value in-place
+ * @p: pointer to a naturally-aligned 32-bit value
+ *
+ * See __swahb32() for details of high and low byte swapping
+ */
+static inline void __swahb32s(uint32_t *p)
+{
+#ifdef __arch_swahb32s
+ __arch_swahb32s(p);
+#else
+ *p = __swahb32p(p);
+#endif
+}
+
+# define swab16 __swab16
+# define swab32 __swab32
+# define swab64 __swab64
+# define swahw32 __swahw32
+# define swahb32 __swahb32
+# define swab16p __swab16p
+# define swab32p __swab32p
+# define swab64p __swab64p
+# define swahw32p __swahw32p
+# define swahb32p __swahb32p
+# define swab16s __swab16s
+# define swab32s __swab32s
+# define swab64s __swab64s
+# define swahw32s __swahw32s
+# define swahb32s __swahb32s
+
+#endif /* _LINUX_SWAB_H */
diff --git a/src/target/firmware/include/uart.h b/src/target/firmware/include/uart.h
new file mode 100644
index 00000000..81d7a156
--- /dev/null
+++ b/src/target/firmware/include/uart.h
@@ -0,0 +1,32 @@
+#ifndef _UART_H
+#define _UART_H
+
+#include <stdint.h>
+
+enum uart_baudrate {
+ UART_38400,
+ UART_57600,
+ UART_115200,
+ UART_230400,
+ UART_460800,
+ UART_614400,
+ UART_921600,
+};
+
+void uart_init(uint8_t uart, uint8_t interrupts);
+void uart_putchar_wait(uint8_t uart, int c);
+int uart_putchar_nb(uint8_t uart, int c);
+int uart_getchar_nb(uint8_t uart, uint8_t *ch);
+int uart_tx_busy(uint8_t uart);
+int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt);
+
+enum uart_irq {
+ UART_IRQ_TX_EMPTY,
+ UART_IRQ_RX_CHAR,
+};
+
+void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on);
+
+void uart_poll(uint8_t uart);
+
+#endif /* _UART_H */
diff --git a/src/target/firmware/include/uwire.h b/src/target/firmware/include/uwire.h
new file mode 100644
index 00000000..6d345534
--- /dev/null
+++ b/src/target/firmware/include/uwire.h
@@ -0,0 +1,7 @@
+#ifndef _UWIRE_H
+#define _UWIRE_H
+
+void uwire_init(void);
+int uwire_xfer(int cs, int bitlen, const void *dout, void *din);
+
+#endif /* _UWIRE_H */
diff --git a/src/target/firmware/layer1/Makefile b/src/target/firmware/layer1/Makefile
new file mode 100644
index 00000000..455a444a
--- /dev/null
+++ b/src/target/firmware/layer1/Makefile
@@ -0,0 +1,9 @@
+
+LIBRARIES+=layer1
+layer1_DIR=layer1
+layer1_SRCS=avg.c agc.c afc.c toa.c sync.c tdma_sched.c tpu_window.c init.c \
+ l23_api.c mframe_sched.c sched_gsmtime.c async.c rfch.c apc.c
+
+layer1_SRCS += prim_pm.c prim_rach.c prim_tx_nb.c prim_rx_nb.c prim_fbsb.c \
+ prim_freq.c prim_utils.c prim_tch.c
+
diff --git a/src/target/firmware/layer1/afc.c b/src/target/firmware/layer1/afc.c
new file mode 100644
index 00000000..a51a1071
--- /dev/null
+++ b/src/target/firmware/layer1/afc.c
@@ -0,0 +1,130 @@
+/* AFC (Automatic Frequency Correction) Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <layer1/afc.h>
+#include <layer1/avg.h>
+#include <calypso/dsp.h>
+
+#define AFC_INITIAL_DAC_VALUE -700
+
+/* Over how many TDMA frames do we want to average? (this may change in dedicated mode) */
+#define AFC_PERIOD 40
+/* How many of our measurements have to be valid? */
+#define AFC_MIN_MUN_VALID 8
+
+/* The actual AFC code */
+
+struct afc_state {
+ struct running_avg ravg; /* running average */
+ int16_t dac_value; /* current DAC output value */
+ uint16_t arfcn;
+};
+
+static void afc_ravg_output(struct running_avg *ravg, int32_t avg);
+
+static struct afc_state afc_state = {
+ .ravg = {
+ .outfn = &afc_ravg_output,
+ .period = AFC_PERIOD,
+ .min_valid = AFC_MIN_MUN_VALID,
+ },
+ .dac_value = AFC_INITIAL_DAC_VALUE,
+};
+
+/* The AFC DAC in the ABB has to be configured as follows:
+ * DAC = 1MHz / 947MHz * FreqErr(Hz) / AFCslop(ppm/LSB)
+ * where:
+ * 947 MHz is the center of EGSM
+ * AFCslope is coded F1.15, thus a normalization factor of 2^15 applies
+ */
+
+#define AFC_NORM_FACTOR_GSM ((1<<15) / 947)
+#define AFC_NORM_FACTOR_DCS ((1<<15) / 1894)
+
+/* we assume 8.769ppb per LSB, equals 0.008769 * 32768 == 287 */
+//#define AFC_SLOPE 320
+#define AFC_SLOPE 287
+
+/* The DSP can measure the frequency error in the following ranges:
+ * FB_MODE0: +/- 20 kHz
+ * FB_MODE1: +/- 4 kHz
+ * Sync Burst: +/- 1 kHz
+ * Normal Burst: +/- 400 Hz
+ */
+
+/* Update the AFC with a frequency error, bypassing averaging */
+void afc_correct(int16_t freq_error, uint16_t arfcn)
+{
+ int32_t afc_norm_factor;
+ int16_t delta;
+
+ switch (gsm_arfcn2band(arfcn)) {
+ case GSM_BAND_900:
+ case GSM_BAND_850:
+ afc_norm_factor = AFC_NORM_FACTOR_GSM;
+ break;
+ default:
+ afc_norm_factor = AFC_NORM_FACTOR_DCS;
+ }
+
+ delta = (int16_t) ((afc_norm_factor * (int32_t)freq_error) / AFC_SLOPE);
+ printd("afc_correct(error=%dHz, arfcn=%u): delta=%d, afc_dac(old=%d,new=%d)\n",
+ freq_error, arfcn, delta, afc_state.dac_value, afc_state.dac_value+delta);
+ afc_state.dac_value += delta;
+
+ /* The AFC DAC has only 13 bits */
+ if (afc_state.dac_value > 4095)
+ afc_state.dac_value = 4095;
+ else if (afc_state.dac_value < -4096)
+ afc_state.dac_value = -4096;
+}
+
+void afc_reset(void)
+{
+ afc_state.dac_value = AFC_INITIAL_DAC_VALUE;
+}
+
+void afc_input(int32_t freq_error, uint16_t arfcn, int valid)
+{
+ afc_state.arfcn = arfcn;
+ runavg_input(&afc_state.ravg, freq_error, valid);
+ runavg_check_output(&afc_state.ravg);
+}
+
+/* callback function for runavg */
+static void afc_ravg_output(struct running_avg *ravg, int32_t avg)
+{
+ afc_correct(avg, afc_state.arfcn);
+}
+
+/* Update DSP with new AFC DAC value to be used for next TDMA frame */
+void afc_load_dsp(void)
+{
+ dsp_api.db_w->d_afc = afc_state.dac_value;
+ dsp_api.db_w->d_ctrl_abb |= (1 << B_AFC);
+}
diff --git a/src/target/firmware/layer1/agc.c b/src/target/firmware/layer1/agc.c
new file mode 100644
index 00000000..b72a6e74
--- /dev/null
+++ b/src/target/firmware/layer1/agc.c
@@ -0,0 +1,62 @@
+/* AFC (Automatic Gain Control) Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+#include <debug.h>
+#include <rffe.h>
+
+#include <layer1/agc.h>
+#include <calypso/dsp.h>
+
+/* compute the input level present at the antenna based on a baseband
+ * power measurement of the DSP at baseband */
+int16_t agc_inp_dbm8_by_pm(int16_t pm)
+{
+ /* pm is in 1/8 dBm at baseband */
+ int16_t total_gain_dbm8;
+
+ /* compute total current gain */
+ total_gain_dbm8 = (system_inherent_gain + rffe_get_gain()) * 8;
+
+ /* subtract gain from power measurement at baseband level */
+ return pm - total_gain_dbm8;
+}
+
+uint8_t agc_il_by_dbm8(int16_t dbm8)
+{
+ uint16_t il;
+
+ /* convert from 1/8 dBm to l1c format: [220..0] in -1/2dBm unit */
+ if (dbm8 >= 0)
+ il = 0;
+ else
+ il = -dbm8;
+
+ /* saturate */
+ if (il > 4 * 255)
+ il = 4 * 255;
+
+ return (uint8_t)(il >> 2);
+}
diff --git a/src/target/firmware/layer1/apc.c b/src/target/firmware/layer1/apc.c
new file mode 100644
index 00000000..480c7607
--- /dev/null
+++ b/src/target/firmware/layer1/apc.c
@@ -0,0 +1,57 @@
+/* APC (Automatic Power Control) Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <errno.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <layer1/apc.h>
+
+/* calibration table defined in board file */
+extern const int16_t dbm2apc_gsm900[];
+extern const int dbm2apc_gsm900_max;
+
+
+/* determine the AUXAPC value by the Tx Power Level */
+int16_t apc_tx_dbm2auxapc(enum gsm_band band, int8_t dbm)
+{
+ if (dbm < 0)
+ return -ERANGE;
+
+ /* FIXME: offsets for different bands! */
+ if (dbm > dbm2apc_gsm900_max)
+ dbm = dbm2apc_gsm900_max;
+
+ return dbm2apc_gsm900[dbm];
+}
+
+/* determine the AUXAPC value by the Tx Power Level */
+int16_t apc_tx_pwrlvl2auxapc(enum gsm_band band, uint8_t lvl)
+{
+ /* convert tx power level to dBm */
+ int dbm = ms_pwr_dbm(band, lvl);
+ if (dbm < 0)
+ return dbm;
+
+ return apc_tx_dbm2auxapc(band, dbm);
+}
diff --git a/src/target/firmware/layer1/async.c b/src/target/firmware/layer1/async.c
new file mode 100644
index 00000000..cb2a2a8c
--- /dev/null
+++ b/src/target/firmware/layer1/async.c
@@ -0,0 +1,159 @@
+/* Asynchronous part of GSM Layer 1 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+
+#include <debug.h>
+#include <arm.h>
+#include <asm/system.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+
+#include <layer1/sync.h>
+#include <layer1/async.h>
+#include <layer1/mframe_sched.h>
+#include <layer1/sched_gsmtime.h>
+#include <layer1/l23_api.h>
+#include <calypso/l1_environment.h>
+
+extern const struct tdma_sched_item rach_sched_set_ul[];
+
+/* safely enable a message into the L1S TX queue */
+void l1a_txq_msgb_enq(struct llist_head *queue, struct msgb *msg)
+{
+ unsigned long flags;
+
+ local_firq_save(flags);
+ msgb_enqueue(queue, msg);
+ local_irq_restore(flags);
+}
+
+void l1a_meas_msgb_set(struct msgb *msg)
+{
+ unsigned long flags;
+
+ local_firq_save(flags);
+ if (l1s.tx_meas)
+ msgb_free(l1s.tx_meas);
+ l1s.tx_meas = msg;
+ local_irq_restore(flags);
+}
+
+/* safely count messages in the L1S TX queue */
+int l1a_txq_msgb_count(struct llist_head *queue)
+{
+ unsigned long flags;
+ int num = 0;
+ struct llist_head *le;
+
+ local_firq_save(flags);
+ llist_for_each(le, queue)
+ num++;
+ local_irq_restore(flags);
+
+ return num;
+}
+
+/* safely flush all pending msgb */
+void l1a_txq_msgb_flush(struct llist_head *queue)
+{
+ struct msgb *msg;
+ unsigned long flags;
+
+ local_firq_save(flags);
+ while ((msg = msgb_dequeue(queue)))
+ msgb_free(msg);
+ local_irq_restore(flags);
+}
+
+/* Enable a repeating multiframe task */
+void l1a_mftask_enable(enum mframe_task task)
+{
+ /* we don't need locking here as L1S only reads mframe.tasks */
+ mframe_enable(task);
+}
+
+/* Disable a repeating multiframe task */
+void l1a_mftask_disable(enum mframe_task task)
+{
+ /* we don't need locking here as L1S only reads mframe.tasks */
+ mframe_disable(task);
+}
+
+/* Set the mask for repeating multiframe tasks */
+void l1a_mftask_set(uint32_t tasks)
+{
+ /* we don't need locking here as L1S only reads mframe.tasks */
+ mframe_set(tasks);
+}
+
+/* Set TCH mode */
+uint8_t l1a_tch_mode_set(uint8_t mode)
+{
+ switch (mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ case GSM48_CMODE_SPEECH_EFR:
+ l1s.tch_mode = mode;
+ break;
+ default:
+ l1s.tch_mode = GSM48_CMODE_SIGN;
+ }
+
+ return l1s.tch_mode;
+}
+
+/* Set Audio routing mode */
+uint8_t l1a_audio_mode_set(uint8_t mode)
+{
+ l1s.audio_mode = mode;
+ return mode;
+}
+
+/* Initialize asynchronous part of Layer1 */
+void l1a_init(void)
+{
+ l1a_l23api_init();
+}
+
+/* Execute pending L1A completions */
+void l1a_compl_execute(void)
+{
+ unsigned long flags;
+ unsigned int scheduled;
+ unsigned int i;
+
+ /* get and reset the currently scheduled tasks */
+ local_firq_save(flags);
+ scheduled = l1s.scheduled_compl;
+ l1s.scheduled_compl = 0;
+ local_irq_restore(flags);
+
+ /* Iterate over list of scheduled completions, call their
+ * respective completion handler */
+ for (i = 0; i < 32; i++) {
+ if (!(scheduled & (1 << i)))
+ continue;
+ /* call completion function */
+ l1s.completion[i](i);
+ }
+}
diff --git a/src/target/firmware/layer1/avg.c b/src/target/firmware/layer1/avg.c
new file mode 100644
index 00000000..a4bf565b
--- /dev/null
+++ b/src/target/firmware/layer1/avg.c
@@ -0,0 +1,57 @@
+/* Averaging Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+
+#include <layer1/avg.h>
+
+/* input a new sample into the averaging process */
+void runavg_input(struct running_avg *ravg, int32_t val, int valid)
+{
+ ravg->num_samples++;
+ if (valid) {
+ ravg->acc_val += val;
+ ravg->num_samples_valid++;
+ }
+}
+
+/* check if sufficient samples have been obtained, and call outfn() */
+int runavg_check_output(struct running_avg *ravg)
+{
+ if (ravg->num_samples < ravg->period)
+ return 0;
+
+ if (ravg->num_samples_valid >= ravg->min_valid) {
+ int32_t avg = ravg->acc_val / ravg->num_samples_valid;
+
+ ravg->outfn(ravg, avg);
+
+ ravg->num_samples = ravg->num_samples_valid = 0;
+ ravg->acc_val = 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
diff --git a/src/target/firmware/layer1/init.c b/src/target/firmware/layer1/init.c
new file mode 100644
index 00000000..e7fde232
--- /dev/null
+++ b/src/target/firmware/layer1/init.c
@@ -0,0 +1,73 @@
+/* OsmocomBB Layer1 initialization */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rffe.h>
+#include <rf/trf6151.h>
+#include <abb/twl3025.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/irq.h>
+
+#include <layer1/sync.h>
+#include <layer1/async.h>
+#include <layer1/l23_api.h>
+
+void layer1_init(void)
+{
+#ifndef CONFIG_TX_ENABLE
+ printf("\n\nTHIS FIRMWARE WAS COMPILED WITHOUT TX SUPPORT!!!\n\n");
+#endif
+
+ /* initialize asynchronous part of L1 */
+ l1a_init();
+ /* initialize TDMA Frame IRQ driven synchronous L1 */
+ l1s_init();
+ /* power up the DSP */
+ dsp_power_on();
+
+ /* Initialize TPU, TSP and TRF drivers */
+ tpu_init();
+ tsp_init();
+
+ rffe_init();
+
+#if 0 /* only if RX TPU window is disabled! */
+ /* Put TWL3025 in downlink mode (includes calibration) */
+ twl3025_downlink(1, 1000);
+#endif
+
+ /* issue the TRF and TWL initialization sequence */
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+
+ /* Disable RTC interrupt as it causes lost TDMA frames */
+ irq_disable(IRQ_RTC_TIMER);
+
+ /* inform l2 and upwards that we are ready for orders */
+ l1ctl_tx_reset(L1CTL_RESET_IND, L1CTL_RES_T_BOOT);
+}
diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c
new file mode 100644
index 00000000..ae39e634
--- /dev/null
+++ b/src/target/firmware/layer1/l23_api.c
@@ -0,0 +1,690 @@
+/* Synchronous part of GSM Layer 1: API to Layer2+ */
+
+/* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#define DEBUG
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <debug.h>
+#include <byteorder.h>
+
+#include <asm/system.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <comm/sercomm.h>
+
+#include <layer1/sync.h>
+#include <layer1/async.h>
+#include <layer1/mframe_sched.h>
+#include <layer1/prim.h>
+#include <layer1/tpu_window.h>
+#include <layer1/sched_gsmtime.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+#include <calypso/sim.h>
+#include <calypso/dsp.h>
+
+#include <l1ctl_proto.h>
+
+/* the size we will allocate struct msgb* for HDLC */
+#define L3_MSG_HEAD 4
+#define L3_MSG_DATA 200
+#define L3_MSG_SIZE (L3_MSG_HEAD + sizeof(struct l1ctl_hdr) + L3_MSG_DATA)
+
+void (*l1a_l23_tx_cb)(struct msgb *msg) = NULL;
+
+void l1_queue_for_l2(struct msgb *msg)
+{
+ if (l1a_l23_tx_cb) {
+ l1a_l23_tx_cb(msg);
+ return;
+ }
+ /* forward via serial for now */
+ sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
+}
+
+enum mf_type {
+ MFNONE,
+ MF51,
+ MF26ODD,
+ MF26EVEN
+};
+static uint32_t chan_nr2mf_task_mask(uint8_t chan_nr, uint8_t neigh_mode)
+{
+ uint8_t cbits = chan_nr >> 3;
+ uint8_t tn = chan_nr & 0x7;
+ uint8_t lch_idx;
+ enum mframe_task master_task = 0;
+ uint32_t neigh_task = 0;
+ enum mf_type multiframe;
+
+ if (cbits == 0x01) {
+ lch_idx = 0;
+ master_task = (tn & 1) ? MF_TASK_TCH_F_ODD : MF_TASK_TCH_F_EVEN;
+ multiframe = (tn & 1) ? MF26ODD : MF26EVEN;
+ } else if ((cbits & 0x1e) == 0x02) {
+ lch_idx = cbits & 0x1;
+ master_task = MF_TASK_TCH_H_0 + lch_idx;
+ } else if ((cbits & 0x1c) == 0x04) {
+ lch_idx = cbits & 0x3;
+ master_task = MF_TASK_SDCCH4_0 + lch_idx;
+ multiframe = MF51;
+ } else if ((cbits & 0x18) == 0x08) {
+ lch_idx = cbits & 0x7;
+ master_task = MF_TASK_SDCCH8_0 + lch_idx;
+ multiframe = MF51;
+#if 0
+ } else if (cbits == 0x10) {
+ /* FIXME: when to do extended BCCH? */
+ master_task = MF_TASK_BCCH_NORM;
+ } else if (cbits == 0x11 || cbits == 0x12) {
+ /* FIXME: how to decide CCCH norm/extd? */
+ master_task = MF_TASK_BCCH_CCCH;
+#endif
+ }
+ switch (neigh_mode) {
+ case NEIGH_MODE_PM:
+ switch (multiframe) {
+ case MF51:
+ neigh_task = (1 << MF_TASK_NEIGH_PM51);
+ break;
+ case MF26EVEN:
+ neigh_task = (1 << MF_TASK_NEIGH_PM26E);
+ break;
+ case MF26ODD:
+ neigh_task = (1 << MF_TASK_NEIGH_PM26O);
+ break;
+ }
+ break;
+ }
+ return (1 << master_task) | neigh_task;
+}
+
+static int chan_nr2dchan_type(uint8_t chan_nr)
+{
+ uint8_t cbits = chan_nr >> 3;
+
+ if (cbits == 0x01) {
+ return GSM_DCHAN_TCH_F;
+ } else if ((cbits & 0x1e) == 0x02) {
+ return GSM_DCHAN_TCH_H;
+ } else if ((cbits & 0x1c) == 0x04) {
+ return GSM_DCHAN_SDCCH_4;
+ } else if ((cbits & 0x18) == 0x08) {
+ return GSM_DCHAN_SDCCH_8;
+ }
+ return GSM_DCHAN_UNKNOWN;
+}
+
+static int chan_nr_is_tch(uint8_t chan_nr)
+{
+ return ((chan_nr >> 3) == 0x01 || /* TCH/F */
+ ((chan_nr >> 3) & 0x1e) == 0x02); /* TCH/H */
+}
+
+static void audio_set_enabled(uint8_t tch_mode, uint8_t audio_mode)
+{
+ if (tch_mode == GSM48_CMODE_SIGN) {
+ twl3025_unit_enable(TWL3025_UNIT_VUL, 0);
+ twl3025_unit_enable(TWL3025_UNIT_VDL, 0);
+ } else {
+ twl3025_unit_enable(TWL3025_UNIT_VUL,
+ !!(audio_mode & AUDIO_TX_MICROPHONE));
+ twl3025_unit_enable(TWL3025_UNIT_VDL,
+ !!(audio_mode & AUDIO_RX_SPEAKER));
+ }
+}
+
+struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
+{
+ struct msgb *msg;
+ struct l1ctl_hdr *l1h;
+
+ msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
+ if (!msg) {
+ while (1) {
+ puts("OOPS. Out of buffers...\n");
+ }
+
+ return NULL;
+ }
+ l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
+ l1h->msg_type = msg_type;
+ l1h->flags = 0;
+
+ msg->l1h = (uint8_t *)l1h;
+
+ return msg;
+}
+
+struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
+ uint16_t arfcn)
+{
+ struct l1ctl_info_dl *dl;
+ struct msgb *msg = l1ctl_msgb_alloc(msg_type);
+
+ dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
+ dl->frame_nr = htonl(fn);
+ dl->snr = snr;
+ dl->band_arfcn = htons(arfcn);
+
+ return msg;
+}
+
+/* receive a L1CTL_FBSB_REQ from L23 */
+static void l1ctl_rx_fbsb_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
+
+ if (sizeof(*sync_req) > msg->len) {
+ printf("Short sync msg. %u\n", msg->len);
+ return;
+ }
+
+ printd("L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
+ ntohs(sync_req->band_arfcn), sync_req->flags);
+
+ /* reset scheduler and hardware */
+ l1s_reset();
+
+ /* pre-set the CCCH mode */
+ l1s.serving_cell.ccch_mode = sync_req->ccch_mode;
+
+ printd("Starting FCCH Recognition\n");
+ l1s_fbsb_req(1, sync_req);
+}
+
+/* receive a L1CTL_DM_EST_REQ from L23 */
+static void l1ctl_rx_dm_est_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
+ struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
+
+ printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
+ ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc);
+
+ /* disable neighbour cell measurement of C0 TS 0 */
+ mframe_disable(MF_TASK_NEIGH_PM51_C0T0);
+
+ /* configure dedicated channel state */
+ l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
+ l1s.dedicated.tsc = est_req->tsc;
+ l1s.dedicated.tn = ul->chan_nr & 0x7;
+ l1s.dedicated.h = est_req->h;
+
+ if (est_req->h) {
+ int i;
+ l1s.dedicated.h1.hsn = est_req->h1.hsn;
+ l1s.dedicated.h1.maio = est_req->h1.maio;
+ l1s.dedicated.h1.n = est_req->h1.n;
+ for (i=0; i<est_req->h1.n; i++)
+ l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]);
+ } else {
+ l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn);
+ }
+
+ /* TCH config */
+ if (chan_nr_is_tch(ul->chan_nr)) {
+ /* Mode */
+ l1a_tch_mode_set(est_req->tch_mode);
+ l1a_audio_mode_set(est_req->audio_mode);
+
+ /* Sync */
+ l1s.tch_sync = 1; /* can be set without locking */
+
+ /* Audio path */
+ audio_set_enabled(est_req->tch_mode, est_req->audio_mode);
+ }
+
+ /* figure out which MF tasks to enable */
+ l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, NEIGH_MODE_PM));
+}
+
+/* receive a L1CTL_DM_FREQ_REQ from L23 */
+static void l1ctl_rx_dm_freq_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
+ struct l1ctl_dm_freq_req *freq_req =
+ (struct l1ctl_dm_freq_req *) ul->payload;
+
+ printd("L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
+ ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
+
+ /* configure dedicated channel state */
+ l1s.dedicated.st_tsc = freq_req->tsc;
+ l1s.dedicated.st_h = freq_req->h;
+
+ if (freq_req->h) {
+ int i;
+ l1s.dedicated.st_h1.hsn = freq_req->h1.hsn;
+ l1s.dedicated.st_h1.maio = freq_req->h1.maio;
+ l1s.dedicated.st_h1.n = freq_req->h1.n;
+ for (i=0; i<freq_req->h1.n; i++)
+ l1s.dedicated.st_h1.ma[i] = ntohs(freq_req->h1.ma[i]);
+ } else {
+ l1s.dedicated.st_h0.arfcn = ntohs(freq_req->h0.band_arfcn);
+ }
+
+ l1a_freq_req(ntohs(freq_req->fn));
+}
+
+/* receive a L1CTL_CRYPTO_REQ from L23 */
+static void l1ctl_rx_crypto_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
+ struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
+ uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
+
+ printd("L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n", cr->algo, key_len);
+
+ if (cr->algo && key_len != 8) {
+ printd("L1CTL_CRYPTO_REQ -> Invalid key\n");
+ return;
+ }
+
+ dsp_load_ciph_param(cr->algo, cr->key);
+}
+
+/* receive a L1CTL_DM_REL_REQ from L23 */
+static void l1ctl_rx_dm_rel_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
+
+ printd("L1CTL_DM_REL_REQ\n");
+ l1a_mftask_set(0);
+ l1s.dedicated.type = GSM_DCHAN_NONE;
+ l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_MAIN]);
+ l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_SACCH]);
+ l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_TRAFFIC]);
+ l1a_meas_msgb_set(NULL);
+ dsp_load_ciph_param(0, NULL);
+ l1a_tch_mode_set(GSM48_CMODE_SIGN);
+ audio_set_enabled(GSM48_CMODE_SIGN, 0);
+ l1s.neigh_pm.n = 0;
+}
+
+/* receive a L1CTL_PARAM_REQ from L23 */
+static void l1ctl_rx_param_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
+ struct l1ctl_par_req *par_req = (struct l1ctl_par_req *) ul->payload;
+
+ printd("L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n", par_req->ta,
+ par_req->tx_power);
+
+ l1s.ta = par_req->ta;
+ l1s.tx_power = par_req->tx_power;
+}
+
+/* receive a L1CTL_RACH_REQ from L23 */
+static void l1ctl_rx_rach_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
+ struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
+
+ printd("L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
+ rach_req->ra, ntohs(rach_req->offset), rach_req->combined);
+
+ l1a_rach_req(ntohs(rach_req->offset), rach_req->combined,
+ rach_req->ra);
+}
+
+/* receive a L1CTL_DATA_REQ from L23 */
+static void l1ctl_rx_data_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
+ struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *) ul->payload;
+ struct llist_head *tx_queue;
+
+ printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
+
+ msg->l3h = data_ind->data;
+ if (ul->link_id & 0x40) {
+ struct gsm48_hdr *gh = (struct gsm48_hdr *)(data_ind->data + 5);
+ if (gh->proto_discr == GSM48_PDISC_RR
+ && gh->msg_type == GSM48_MT_RR_MEAS_REP) {
+ printd("updating measurement report\n");
+ l1a_meas_msgb_set(msg);
+ return;
+ }
+ tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH];
+ } else
+ tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN];
+
+ printd("ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n",
+ ul, ul->payload, data_ind, data_ind->data, msg->l3h);
+
+ l1a_txq_msgb_enq(tx_queue, msg);
+}
+
+/* receive a L1CTL_PM_REQ from L23 */
+static void l1ctl_rx_pm_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
+
+ switch (pm_req->type) {
+ case 1:
+ l1s.pm.mode = 1;
+ l1s.pm.range.arfcn_start =
+ ntohs(pm_req->range.band_arfcn_from);
+ l1s.pm.range.arfcn_next =
+ ntohs(pm_req->range.band_arfcn_from);
+ l1s.pm.range.arfcn_end =
+ ntohs(pm_req->range.band_arfcn_to);
+ printf("L1CTL_PM_REQ start=%u end=%u\n",
+ l1s.pm.range.arfcn_start, l1s.pm.range.arfcn_end);
+ break;
+ }
+ l1s_reset_hw(); /* must reset, otherwise measurement results are delayed */
+ l1s_pm_test(1, l1s.pm.range.arfcn_next);
+}
+
+/* Transmit a L1CTL_RESET_IND or L1CTL_RESET_CONF */
+void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(msg_type);
+ struct l1ctl_reset *reset_resp;
+ reset_resp = (struct l1ctl_reset *)
+ msgb_put(msg, sizeof(*reset_resp));
+ reset_resp->type = reset_type;
+
+ l1_queue_for_l2(msg);
+}
+
+/* receive a L1CTL_RESET_REQ from L23 */
+static void l1ctl_rx_reset_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_reset *reset_req =
+ (struct l1ctl_reset *) l1h->data;
+
+ switch (reset_req->type) {
+ case L1CTL_RES_T_FULL:
+ printf("L1CTL_RESET_REQ: FULL!\n");
+ l1s_reset();
+ l1s_reset_hw();
+ audio_set_enabled(GSM48_CMODE_SIGN, 0);
+ l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
+ break;
+ case L1CTL_RES_T_SCHED:
+ printf("L1CTL_RESET_REQ: SCHED!\n");
+ l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
+ sched_gsmtime_reset();
+ break;
+ default:
+ printf("unknown L1CTL_RESET_REQ type\n");
+ break;
+ }
+}
+
+/* Transmit a L1CTL_CCCH_MODE_CONF */
+static void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
+ struct l1ctl_ccch_mode_conf *mode_conf;
+ mode_conf = (struct l1ctl_ccch_mode_conf *)
+ msgb_put(msg, sizeof(*mode_conf));
+ mode_conf->ccch_mode = ccch_mode;
+
+ l1_queue_for_l2(msg);
+}
+
+/* receive a L1CTL_CCCH_MODE_REQ from L23 */
+static void l1ctl_rx_ccch_mode_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_ccch_mode_req *ccch_mode_req =
+ (struct l1ctl_ccch_mode_req *) l1h->data;
+ uint8_t ccch_mode = ccch_mode_req->ccch_mode;
+
+ /* pre-set the CCCH mode */
+ l1s.serving_cell.ccch_mode = ccch_mode;
+
+ /* Update task */
+ mframe_disable(MF_TASK_CCCH_COMB);
+ mframe_disable(MF_TASK_CCCH);
+
+ if (ccch_mode == CCCH_MODE_COMBINED)
+ mframe_enable(MF_TASK_CCCH_COMB);
+ else if (ccch_mode == CCCH_MODE_NON_COMBINED)
+ mframe_enable(MF_TASK_CCCH);
+
+ l1ctl_tx_ccch_mode_conf(ccch_mode);
+}
+
+/* Transmit a L1CTL_TCH_MODE_CONF */
+static void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode)
+{
+ struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
+ struct l1ctl_tch_mode_conf *mode_conf;
+ mode_conf = (struct l1ctl_tch_mode_conf *)
+ msgb_put(msg, sizeof(*mode_conf));
+ mode_conf->tch_mode = tch_mode;
+ mode_conf->audio_mode = audio_mode;
+
+ l1_queue_for_l2(msg);
+}
+
+/* receive a L1CTL_TCH_MODE_REQ from L23 */
+static void l1ctl_rx_tch_mode_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_tch_mode_req *tch_mode_req =
+ (struct l1ctl_tch_mode_req *) l1h->data;
+ uint8_t tch_mode = tch_mode_req->tch_mode;
+ uint8_t audio_mode = tch_mode_req->audio_mode;
+
+ printd("L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n",
+ tch_mode, audio_mode);
+ tch_mode = l1a_tch_mode_set(tch_mode);
+ audio_mode = l1a_audio_mode_set(audio_mode);
+
+ audio_set_enabled(tch_mode, audio_mode);
+
+ l1s.tch_sync = 1; /* Needed for audio to work */
+
+ l1ctl_tx_tch_mode_conf(tch_mode, audio_mode);
+}
+
+/* receive a L1CTL_NEIGH_PM_REQ from L23 */
+static void l1ctl_rx_neigh_pm_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_neigh_pm_req *pm_req =
+ (struct l1ctl_neigh_pm_req *) l1h->data;
+ int i;
+
+ /* reset list in order to prevent race condition */
+ l1s.neigh_pm.n = 0; /* atomic */
+ l1s.neigh_pm.second = 0;
+ /* now reset pointer and fill list */
+ l1s.neigh_pm.pos = 0;
+ l1s.neigh_pm.running = 0;
+ for (i = 0; i < pm_req->n; i++) {
+ l1s.neigh_pm.band_arfcn[i] = ntohs(pm_req->band_arfcn[i]);
+ l1s.neigh_pm.tn[i] = pm_req->tn[i];
+ }
+ printf("L1CTL_NEIGH_PM_REQ new list with %u entries\n", pm_req->n);
+ l1s.neigh_pm.n = pm_req->n; /* atomic */
+
+ /* on C0 enable PM on frame 51 */
+ if (l1s.dedicated.type == GSM_DCHAN_NONE)
+ mframe_enable(MF_TASK_NEIGH_PM51_C0T0);
+}
+
+/* receive a L1CTL_TRAFFIC_REQ from L23 */
+static void l1ctl_rx_traffic_req(struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
+ struct l1ctl_traffic_req *tr = (struct l1ctl_traffic_req *) ul->payload;
+ int num = 0;
+
+ /* printd("L1CTL_TRAFFIC_REQ\n"); */ /* Very verbose, can overwelm serial */
+
+ msg->l2h = tr->data;
+
+ num = l1a_txq_msgb_count(&l1s.tx_queue[L1S_CHAN_TRAFFIC]);
+ if (num >= 4) {
+ printd("dropping traffic frame\n");
+ msgb_free(msg);
+ return;
+ }
+
+ l1a_txq_msgb_enq(&l1s.tx_queue[L1S_CHAN_TRAFFIC], msg);
+}
+
+static void l1ctl_sim_req(struct msgb *msg)
+{
+ uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
+ uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
+
+#if 1 /* for debugging only */
+ {
+ int i;
+ printf("SIM Request (%u): ", len);
+ for (i = 0; i < len; i++)
+ printf("%02x ", data[i]);
+ puts("\n");
+ }
+#endif
+
+ sim_apdu(len, data);
+}
+
+static struct llist_head l23_rx_queue = LLIST_HEAD_INIT(l23_rx_queue);
+
+/* callback from SERCOMM when L2 sends a message to L1 */
+void l1a_l23_rx(uint8_t dlci, struct msgb *msg)
+{
+ unsigned long flags;
+
+ local_firq_save(flags);
+ msgb_enqueue(&l23_rx_queue, msg);
+ local_irq_restore(flags);
+}
+
+void l1a_l23_handler(void)
+{
+ struct msgb *msg;
+ struct l1ctl_hdr *l1h;
+ unsigned long flags;
+
+ local_firq_save(flags);
+ msg = msgb_dequeue(&l23_rx_queue);
+ local_irq_restore(flags);
+ if (!msg)
+ return;
+
+ l1h = (struct l1ctl_hdr *) msg->data;
+
+#if 0
+ {
+ int i;
+ printf("l1a_l23_rx_cb (%u): ", msg->len);
+ for (i = 0; i < msg->len; i++)
+ printf("%02x ", msg->data[i]);
+ puts("\n");
+ }
+#endif
+
+ msg->l1h = msg->data;
+
+ if (sizeof(*l1h) > msg->len) {
+ printf("l1a_l23_cb: Short message. %u\n", msg->len);
+ goto exit_msgbfree;
+ }
+
+ switch (l1h->msg_type) {
+ case L1CTL_FBSB_REQ:
+ l1ctl_rx_fbsb_req(msg);
+ break;
+ case L1CTL_DM_EST_REQ:
+ l1ctl_rx_dm_est_req(msg);
+ break;
+ case L1CTL_DM_REL_REQ:
+ l1ctl_rx_dm_rel_req(msg);
+ break;
+ case L1CTL_PARAM_REQ:
+ l1ctl_rx_param_req(msg);
+ break;
+ case L1CTL_DM_FREQ_REQ:
+ l1ctl_rx_dm_freq_req(msg);
+ break;
+ case L1CTL_CRYPTO_REQ:
+ l1ctl_rx_crypto_req(msg);
+ break;
+ case L1CTL_RACH_REQ:
+ l1ctl_rx_rach_req(msg);
+ break;
+ case L1CTL_DATA_REQ:
+ l1ctl_rx_data_req(msg);
+ /* we have to keep the msgb, not free it! */
+ goto exit_nofree;
+ case L1CTL_PM_REQ:
+ l1ctl_rx_pm_req(msg);
+ break;
+ case L1CTL_RESET_REQ:
+ l1ctl_rx_reset_req(msg);
+ break;
+ case L1CTL_CCCH_MODE_REQ:
+ l1ctl_rx_ccch_mode_req(msg);
+ break;
+ case L1CTL_TCH_MODE_REQ:
+ l1ctl_rx_tch_mode_req(msg);
+ break;
+ case L1CTL_NEIGH_PM_REQ:
+ l1ctl_rx_neigh_pm_req(msg);
+ break;
+ case L1CTL_TRAFFIC_REQ:
+ l1ctl_rx_traffic_req(msg);
+ /* we have to keep the msgb, not free it! */
+ goto exit_nofree;
+ case L1CTL_SIM_REQ:
+ l1ctl_sim_req(msg);
+ break;
+ }
+
+exit_msgbfree:
+ msgb_free(msg);
+exit_nofree:
+ return;
+}
+
+void l1a_l23api_init(void)
+{
+ sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx);
+}
+
diff --git a/src/target/firmware/layer1/mframe_sched.c b/src/target/firmware/layer1/mframe_sched.c
new file mode 100644
index 00000000..f3a6b433
--- /dev/null
+++ b/src/target/firmware/layer1/mframe_sched.c
@@ -0,0 +1,494 @@
+/* GSM Multiframe Scheduler Implementation (on top of TDMA sched) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <debug.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <layer1/prim.h>
+#include <layer1/sync.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/mframe_sched.h>
+
+/* A multiframe operation which can be scheduled for a multiframe */
+struct mframe_sched_item {
+ /* The TDMA scheduler item that shall be scheduled */
+ const struct tdma_sched_item *sched_set;
+ /* Which modulo shall be used on the frame number */
+ uint16_t modulo;
+ /* At which number inside the modulo shall we be scheduled */
+ uint16_t frame_nr;
+ /* bit-mask of flags */
+ uint16_t flags;
+};
+
+/* FIXME: properly clean this up */
+#define NB_QUAD_DL nb_sched_set
+#define NB_QUAD_FH_DL NB_QUAD_DL
+#define NB_QUAD_UL nb_sched_set_ul
+#define NB_QUAD_FH_UL NB_QUAD_UL
+#define NEIGH_PM neigh_pm_sched_set
+
+/* BCCH Normal */
+static const struct mframe_sched_item mf_bcch_norm[] = {
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 2 },
+ { .sched_set = NULL }
+};
+
+/* BCCH Extended */
+static const struct mframe_sched_item mf_bcch_ext[] = {
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
+ { .sched_set = NULL }
+};
+
+/* Full CCCH in a pure BCCH + CCCH C0T0 */
+static const struct mframe_sched_item mf_ccch[] = {
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 12 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 16 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 22 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 26 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 32 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 36 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 42 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 46 },
+ { .sched_set = NULL }
+};
+
+/* Full CCCH in a combined CCCH on C0T0 */
+static const struct mframe_sched_item mf_ccch_comb[] = {
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 12 },
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 16 },
+ { .sched_set = NULL }
+};
+
+/* SDCCH/4 in a combined CCCH on C0T0, cannot be FH */
+static const struct mframe_sched_item mf_sdcch4_0[] = {
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 22 },
+ { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 22+15 },
+ { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 42,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 42+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch4_1[] = {
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 26 },
+ { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 26+15 },
+ { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 46,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 46+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch4_2[] = {
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 32 },
+ { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 32+15 },
+ { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+42,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+42+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch4_3[] = {
+ { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 36 },
+ { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 36+15 },
+ { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+46,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+46+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+
+/* SDCCH/8, can be frequency hopping (FH) */
+static const struct mframe_sched_item mf_sdcch8_0[] = {
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 0 },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 0+15 },
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 32,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 32+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch8_1[] = {
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 4 },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 4+15 },
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 36,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 36+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch8_2[] = {
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 8 },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 8+15 },
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 40,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 40+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch8_3[] = {
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 12 },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 12+15 },
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 44,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 44+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch8_4[] = {
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 16 },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 16+15 },
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+32,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+32+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch8_5[] = {
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 20 },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 20+15 },
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+36,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+36+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch8_6[] = {
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 24 },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 24+15 },
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+40,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+40+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_sdcch8_7[] = {
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 28 },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 28+15 },
+ { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+44,
+ .flags = MF_F_SACCH },
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+44+15,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+
+/* Measurement for MF 51 C0 */
+static const struct mframe_sched_item mf_neigh_pm51_c0t0[] = {
+ { .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 0 },
+ { .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 10 },
+ { .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 20 },
+ { .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 30 },
+ { .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 40 },
+ { .sched_set = NULL }
+};
+
+/* Measurement for MF 51 */
+static const struct mframe_sched_item mf_neigh_pm51[] = {
+ { .sched_set = NEIGH_PM , .modulo = 51, .frame_nr = 50 },
+ { .sched_set = NULL }
+};
+
+/* TCH */
+#define TCH tch_sched_set
+#define TCH_A tch_a_sched_set
+#define TCH_D tch_d_sched_set
+
+static const struct mframe_sched_item mf_tch_f_even[] = {
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 0 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 1 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 2 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 3 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 4 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 5 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 6 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 7 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 8 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 9 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 10 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 11 },
+ { .sched_set = TCH_A, .modulo = 26, .frame_nr = 12,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+
+static const struct mframe_sched_item mf_tch_f_odd[] = {
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 0 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 1 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 2 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 3 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 4 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 5 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 6 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 7 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 8 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 9 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 10 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 11 },
+ { .sched_set = TCH_A, .modulo = 26, .frame_nr = 25,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+
+static const struct mframe_sched_item mf_tch_h_0[] = {
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 0 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 1 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 2 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 3 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 4 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 5 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 6 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 7 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 8 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 9 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 10 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 11 },
+ { .sched_set = TCH_A, .modulo = 26, .frame_nr = 12,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+
+static const struct mframe_sched_item mf_tch_h_1[] = {
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 0 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 1 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 2 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 3 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 4 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 5 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 6 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 7 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 8 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 9 },
+ { .sched_set = TCH_D, .modulo = 13, .frame_nr = 10 },
+ { .sched_set = TCH, .modulo = 13, .frame_nr = 11 },
+ { .sched_set = TCH_A, .modulo = 26, .frame_nr = 25,
+ .flags = MF_F_SACCH },
+ { .sched_set = NULL }
+};
+
+/* Measurement for MF 26 */
+static const struct mframe_sched_item mf_neigh_pm26_even[] = {
+ { .sched_set = NEIGH_PM , .modulo = 26, .frame_nr = 25 },
+ { .sched_set = NULL }
+};
+static const struct mframe_sched_item mf_neigh_pm26_odd[] = {
+ { .sched_set = NEIGH_PM , .modulo = 26, .frame_nr = 12 },
+ { .sched_set = NULL }
+};
+
+/* Test TX */
+static const struct mframe_sched_item mf_tx_all_nb[] = {
+ { .sched_set = NB_QUAD_FH_UL, .modulo = 4, .frame_nr = 0 },
+ { .sched_set = NULL }
+};
+
+static const struct mframe_sched_item *sched_set_for_task[32] = {
+ [MF_TASK_BCCH_NORM] = mf_bcch_norm,
+ [MF_TASK_BCCH_EXT] = mf_bcch_ext,
+ [MF_TASK_CCCH] = mf_ccch,
+ [MF_TASK_CCCH_COMB] = mf_ccch_comb,
+
+ [MF_TASK_SDCCH4_0] = mf_sdcch4_0,
+ [MF_TASK_SDCCH4_1] = mf_sdcch4_1,
+ [MF_TASK_SDCCH4_2] = mf_sdcch4_2,
+ [MF_TASK_SDCCH4_3] = mf_sdcch4_3,
+
+ [MF_TASK_SDCCH8_0] = mf_sdcch8_0,
+ [MF_TASK_SDCCH8_1] = mf_sdcch8_1,
+ [MF_TASK_SDCCH8_2] = mf_sdcch8_2,
+ [MF_TASK_SDCCH8_3] = mf_sdcch8_3,
+ [MF_TASK_SDCCH8_4] = mf_sdcch8_4,
+ [MF_TASK_SDCCH8_5] = mf_sdcch8_5,
+ [MF_TASK_SDCCH8_6] = mf_sdcch8_6,
+ [MF_TASK_SDCCH8_7] = mf_sdcch8_7,
+
+ [MF_TASK_TCH_F_EVEN] = mf_tch_f_even,
+ [MF_TASK_TCH_F_ODD] = mf_tch_f_odd,
+ [MF_TASK_TCH_H_0] = mf_tch_h_0,
+ [MF_TASK_TCH_H_1] = mf_tch_h_1,
+
+ [MF_TASK_NEIGH_PM51_C0T0] = mf_neigh_pm51_c0t0,
+ [MF_TASK_NEIGH_PM51] = mf_neigh_pm51,
+ [MF_TASK_NEIGH_PM26E] = mf_neigh_pm26_even,
+ [MF_TASK_NEIGH_PM26O] = mf_neigh_pm26_odd,
+
+ [MF_TASK_UL_ALL_NB] = mf_tx_all_nb,
+};
+
+/* encodes a channel number according to 08.58 Chapter 9.3.1 */
+uint8_t mframe_task2chan_nr(enum mframe_task mft, uint8_t ts)
+{
+ uint8_t cbits;
+
+ switch (mft) {
+ case MF_TASK_BCCH_NORM:
+ case MF_TASK_BCCH_EXT:
+ cbits = 0x10;
+ break;
+ case MF_TASK_CCCH:
+ case MF_TASK_CCCH_COMB:
+ cbits = 0x12;
+ break;
+ case MF_TASK_SDCCH4_0:
+ cbits = 0x04 + 0;
+ break;
+ case MF_TASK_SDCCH4_1:
+ cbits = 0x04 + 1;
+ break;
+ case MF_TASK_SDCCH4_2:
+ cbits = 0x04 + 2;
+ break;
+ case MF_TASK_SDCCH4_3:
+ cbits = 0x04 + 3;
+ break;
+ case MF_TASK_SDCCH8_0:
+ cbits = 0x08 + 0;
+ break;
+ case MF_TASK_SDCCH8_1:
+ cbits = 0x08 + 1;
+ break;
+ case MF_TASK_SDCCH8_2:
+ cbits = 0x08 + 2;
+ break;
+ case MF_TASK_SDCCH8_3:
+ cbits = 0x08 + 3;
+ break;
+ case MF_TASK_SDCCH8_4:
+ cbits = 0x08 + 4;
+ break;
+ case MF_TASK_SDCCH8_5:
+ cbits = 0x08 + 5;
+ break;
+ case MF_TASK_SDCCH8_6:
+ cbits = 0x08 + 6;
+ break;
+ case MF_TASK_SDCCH8_7:
+ cbits = 0x08 + 7;
+ break;
+ case MF_TASK_TCH_F_EVEN:
+ case MF_TASK_TCH_F_ODD:
+ cbits = 0x01;
+ break;
+ case MF_TASK_TCH_H_0:
+ cbits = 0x02 + 0;
+ break;
+ case MF_TASK_TCH_H_1:
+ cbits = 0x02 + 1;
+ break;
+ case MF_TASK_UL_ALL_NB:
+ /* ERROR: cannot express as channel number */
+ cbits = 0;
+ break;
+ }
+
+ return (cbits << 3) | (ts & 0x7);
+}
+
+/* how many TDMA frame ticks should we schedule events ahead? */
+#define SCHEDULE_AHEAD 2
+
+/* how long do we need to tell the DSP in advance what we want to do? */
+#define SCHEDULE_LATENCY 1
+
+/* (test and) schedule one particular sched_item_set by means of the TDMA scheduler */
+static void mframe_schedule_set(enum mframe_task task_id)
+{
+ const struct mframe_sched_item *set = sched_set_for_task[task_id];
+ const struct mframe_sched_item *si;
+
+ for (si = set; si->sched_set != NULL; si++) {
+ unsigned int trigger = si->frame_nr % si->modulo;
+ unsigned int current = (l1s.current_time.fn + SCHEDULE_AHEAD) % si->modulo;
+ if (current == trigger) {
+ uint32_t fn;
+ int rv;
+
+ /* Schedule the set */
+ /* FIXME: what to do with SACCH Flag etc? */
+ rv = tdma_schedule_set(SCHEDULE_AHEAD-SCHEDULE_LATENCY,
+ si->sched_set, task_id | (si->flags<<8));
+
+ /* Compute the next safe time to queue a DSP command */
+ fn = l1s.current_time.fn;
+ ADD_MODULO(fn, rv - 2, GSM_MAX_FN); /* -2 = worst case last dsp command */
+ if ((fn > l1s.mframe_sched.safe_fn) ||
+ (l1s.mframe_sched.safe_fn >= GSM_MAX_FN))
+ l1s.mframe_sched.safe_fn = fn;
+ }
+ }
+}
+
+/* Enable a specific task */
+void mframe_enable(enum mframe_task task_id)
+{
+ l1s.mframe_sched.tasks_tgt |= (1 << task_id);
+}
+
+/* Disable a specific task */
+void mframe_disable(enum mframe_task task_id)
+{
+ l1s.mframe_sched.tasks_tgt &= ~(1 << task_id);
+}
+
+/* Replace the current active set by the new one */
+void mframe_set(uint32_t tasks)
+{
+ l1s.mframe_sched.tasks_tgt = tasks;
+}
+
+/* Schedule mframe_sched_items according to current MF TASK list */
+void mframe_schedule(void)
+{
+ unsigned int i;
+ int fn_diff;
+
+ /* Try to enable/disable task to meet target bitmap */
+ fn_diff = l1s.mframe_sched.safe_fn - l1s.current_time.fn;
+ if ((fn_diff <= 0) || (fn_diff >= (GSM_MAX_FN>>1)) ||
+ (l1s.mframe_sched.safe_fn >= GSM_MAX_FN))
+ /* If nothing is in the way, enable new tasks */
+ l1s.mframe_sched.tasks = l1s.mframe_sched.tasks_tgt;
+ else
+ /* Else, Disable only */
+ l1s.mframe_sched.tasks &= l1s.mframe_sched.tasks_tgt;
+
+ /* Schedule any active pending set */
+ for (i = 0; i < 32; i++) {
+ if (l1s.mframe_sched.tasks & (1 << i))
+ mframe_schedule_set(i);
+ }
+}
+
+/* reset the scheduler, disabling all tasks */
+void mframe_reset(void)
+{
+ l1s.mframe_sched.tasks = 0;
+ l1s.mframe_sched.tasks_tgt = 0;
+ l1s.mframe_sched.safe_fn = -1UL; /* Force safe */
+}
+
diff --git a/src/target/firmware/layer1/prim_fbsb.c b/src/target/firmware/layer1/prim_fbsb.c
new file mode 100644
index 00000000..e849240b
--- /dev/null
+++ b/src/target/firmware/layer1/prim_fbsb.c
@@ -0,0 +1,575 @@
+/* Layer 1 - FCCH and SCH burst handling */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <rffe.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+
+#include <layer1/sync.h>
+#include <layer1/afc.h>
+#include <layer1/toa.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/mframe_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+#include <layer1/agc.h>
+
+#include <l1ctl_proto.h>
+
+#define FB0_RETRY_COUNT 3
+#define AFC_RETRY_COUNT 30
+
+extern uint16_t rf_arfcn; // TODO
+
+struct mon_state {
+ uint32_t fnr_report; /* frame number when DSP reported it */
+ int attempt; /* which attempt was this ? */
+
+ int16_t toa;
+ uint16_t pm;
+ uint16_t angle;
+ uint16_t snr;
+
+ /* computed values */
+ int16_t freq_diff;
+
+ /* Sync Burst (SB) */
+ uint8_t bsic;
+ struct gsm_time time;
+};
+
+struct l1a_fb_state {
+ struct mon_state mon;
+ struct l1ctl_fbsb_req req;
+ int16_t initial_freq_err;
+ uint8_t fb_retries;
+ uint8_t afc_retries;
+};
+
+static struct l1a_fb_state fbs;
+static struct mon_state *last_fb = &fbs.mon;
+
+static void dump_mon_state(struct mon_state *fb)
+{
+#if 0
+ printf("(%u:%u): TOA=%5u, Power=%4ddBm, Angle=%5dHz, "
+ "SNR=%04x(%d.%u) OFFSET=%u SYNCHRO=%u\n",
+ fb->fnr_report, fb->attempt, fb->toa,
+ agc_inp_dbm8_by_pm(fb->pm)/8, ANGLE_TO_FREQ(fb->angle),
+ fb->snr, l1s_snr_int(fb->snr), l1s_snr_fract(fb->snr),
+ tpu_get_offset(), tpu_get_synchro());
+#else
+ printf("(%u:%u): TOA=%5u, Power=%4ddBm, Angle=%5dHz\n",
+ fb->fnr_report, fb->attempt, fb->toa,
+ agc_inp_dbm8_by_pm(fb->pm)/8, ANGLE_TO_FREQ(fb->angle));
+#endif
+}
+
+static int l1ctl_fbsb_resp(uint8_t res)
+{
+ struct msgb *msg;
+ struct l1ctl_fbsb_conf *resp;
+
+ msg = l1_create_l2_msg(L1CTL_FBSB_CONF, fbs.mon.time.fn,
+ l1s_snr_int(fbs.mon.snr),
+ fbs.req.band_arfcn);
+ if (!msg)
+ return -ENOMEM;
+
+ resp = (struct l1ctl_fbsb_conf *) msgb_put(msg, sizeof(*resp));
+ resp->initial_freq_err = htons(fbs.initial_freq_err);
+ resp->result = res;
+ resp->bsic = fbs.mon.bsic;
+
+ /* no need to set BSIC, as it is never used here */
+ l1_queue_for_l2(msg);
+
+ return 0;
+}
+
+/* SCH Burst Detection ********************************************************/
+
+/* determine the GSM time and BSIC from a Sync Burst */
+static uint8_t l1s_decode_sb(struct gsm_time *time, uint32_t sb)
+{
+ uint8_t bsic = (sb >> 2) & 0x3f;
+ uint8_t t3p;
+
+ memset(time, 0, sizeof(*time));
+
+ /* TS 05.02 Chapter 3.3.2.2.1 SCH Frame Numbers */
+ time->t1 = ((sb >> 23) & 1) | ((sb >> 7) & 0x1fe) | ((sb << 9) & 0x600);
+ time->t2 = (sb >> 18) & 0x1f;
+ t3p = ((sb >> 24) & 1) | ((sb >> 15) & 6);
+ time->t3 = t3p*10 + 1;
+
+ /* TS 05.02 Chapter 4.3.3 TDMA frame number */
+ time->fn = gsm_gsmtime2fn(time);
+
+ time->tc = (time->fn / 51) % 8;
+
+ return bsic;
+}
+
+static void read_sb_result(struct mon_state *st, int attempt)
+{
+ st->toa = dsp_api.db_r->a_serv_demod[D_TOA];
+ st->pm = dsp_api.db_r->a_serv_demod[D_PM]>>3;
+ st->angle = dsp_api.db_r->a_serv_demod[D_ANGLE];
+ st->snr = dsp_api.db_r->a_serv_demod[D_SNR];
+
+ st->freq_diff = ANGLE_TO_FREQ(st->angle);
+ st->fnr_report = l1s.current_time.fn;
+ st->attempt = attempt;
+
+ dump_mon_state(st);
+
+ if (st->snr > AFC_SNR_THRESHOLD)
+ afc_input(st->freq_diff, rf_arfcn, 1);
+ else
+ afc_input(st->freq_diff, rf_arfcn, 0);
+
+ dsp_api.r_page_used = 1;
+}
+
+/* Note: When we get the SB response, it is 2 TDMA frames after the SB
+ * actually happened, as it is a "C W W R" task */
+#define SB2_LATENCY 2
+
+static int l1s_sbdet_resp(__unused uint8_t p1, uint8_t attempt,
+ __unused uint16_t p3)
+{
+ uint32_t sb;
+ int qbits, fn_offset;
+ struct l1_cell_info *cinfo = &l1s.serving_cell;
+ int fnr_delta, bits_delta;
+ struct l1ctl_sync_new_ccch_resp *l1;
+ struct msgb *msg;
+
+ putchart('s');
+
+ if (dsp_api.db_r->a_sch[0] & (1<<B_SCH_CRC)) {
+ /* mark READ page as being used */
+ dsp_api.r_page_used = 1;
+
+ /* after 2nd attempt, we failed */
+ if (attempt == 2) {
+ last_fb->attempt = 13;
+ l1s_compl_sched(L1_COMPL_FB);
+ }
+
+ /* after 1st attempt, we simply wait for 2nd */
+ return 0;
+ }
+
+ printf("SB%d ", attempt);
+ read_sb_result(last_fb, attempt);
+
+ sb = dsp_api.db_r->a_sch[3] | dsp_api.db_r->a_sch[4] << 16;
+ fbs.mon.bsic = l1s_decode_sb(&fbs.mon.time, sb);
+ printf("=> SB 0x%08x: BSIC=%u ", sb, fbs.mon.bsic);
+ l1s_time_dump(&fbs.mon.time);
+
+ l1s.serving_cell.bsic = fbs.mon.bsic;
+
+ /* calculate synchronisation value (TODO: only complete for qbits) */
+ last_fb->toa -= 23;
+ qbits = last_fb->toa * 4;
+ fn_offset = l1s.current_time.fn; // TODO
+
+ if (qbits > QBITS_PER_TDMA) {
+ qbits -= QBITS_PER_TDMA;
+ fn_offset -= 1;
+ } else if (qbits < 0) {
+ qbits += QBITS_PER_TDMA;
+ fn_offset += 1;
+ }
+
+ fnr_delta = last_fb->fnr_report - attempt;
+ bits_delta = fnr_delta * BITS_PER_TDMA;
+
+ cinfo->fn_offset = fnr_delta;
+ cinfo->time_alignment = qbits;
+ cinfo->arfcn = rf_arfcn;
+
+ if (last_fb->toa > bits_delta)
+ printf("=> DSP reports SB in bit that is %d bits in the "
+ "future?!?\n", last_fb->toa - bits_delta);
+ else
+ printf(" qbits=%u\n", qbits);
+
+ synchronize_tdma(&l1s.serving_cell);
+
+ /* if we have recived a SYNC burst, update our local GSM time */
+ gsm_fn2gsmtime(&l1s.current_time, fbs.mon.time.fn + SB2_LATENCY);
+ /* compute next time from new current time */
+ l1s.next_time = l1s.current_time;
+ l1s_time_inc(&l1s.next_time, 1);
+
+ /* If we call tdma_sched_reset(), which is only needed if there
+ * are further l1s_sbdet_resp() scheduled, we will bring
+ * dsp_api.db_r and dsp_api.db_w out of sync because we changed
+ * dsp_api.db_w for l1s_sbdet_cmd() and canceled
+ * l1s_sbdet_resp() which would change dsp_api.db_r. The DSP
+ * however expects dsp_api.db_w and dsp_api.db_r to be in sync
+ * (either "0 - 0" or "1 - 1"). So we have to bring dsp_api.db_w
+ * and dsp_api.db_r into sync again, otherwise NB reading will
+ * complain. We probably don't need the Abort command and could
+ * just bring dsp_api.db_w and dsp_api.db_r into sync. */
+ if (attempt != 2) {
+ tdma_sched_reset();
+ l1s_dsp_abort();
+ }
+
+ l1s_reset_hw();
+ /* enable the MF Task for BCCH reading */
+ mframe_enable(MF_TASK_BCCH_NORM);
+ if (l1s.serving_cell.ccch_mode == CCCH_MODE_COMBINED)
+ mframe_enable(MF_TASK_CCCH_COMB);
+ else if (l1s.serving_cell.ccch_mode == CCCH_MODE_NON_COMBINED)
+ mframe_enable(MF_TASK_CCCH);
+
+ l1s_compl_sched(L1_COMPL_FB);
+
+ return 0;
+}
+
+static int l1s_sbdet_cmd(__unused uint8_t p1, __unused uint8_t p2,
+ __unused uint16_t p3)
+{
+ putchart('S');
+
+ fbs.mon.bsic = 0;
+ fbs.mon.time.fn = 0;
+
+ dsp_api.db_w->d_task_md = SB_DSP_TASK;
+ dsp_api.ndb->d_fb_mode = 0; /* wideband search */
+
+ /* Program TPU */
+ l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_SB, 0);
+
+ return 0;
+}
+
+/* This is how it is done by the TSM30 */
+static const struct tdma_sched_item sb_sched_set[] = {
+ SCHED_ITEM_DT(l1s_sbdet_cmd, 0, 0, 1), SCHED_END_FRAME(),
+ SCHED_ITEM_DT(l1s_sbdet_cmd, 0, 0, 2), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sbdet_resp, -4, 0, 1), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_sbdet_resp, -4, 0, 2), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
+void l1s_sb_test(uint8_t base_fn)
+{
+ tdma_schedule_set(base_fn, sb_sched_set, 0);
+}
+/* FCCH Burst *****************************************************************/
+
+static int read_fb_result(struct mon_state *st, int attempt)
+{
+ st->toa = dsp_api.ndb->a_sync_demod[D_TOA];
+ st->pm = dsp_api.ndb->a_sync_demod[D_PM]>>3;
+ st->angle = dsp_api.ndb->a_sync_demod[D_ANGLE];
+ st->snr = dsp_api.ndb->a_sync_demod[D_SNR];
+
+ //last_fb->angle = clip_int16(last_fb->angle, AFC_MAX_ANGLE);
+ st->freq_diff = ANGLE_TO_FREQ(last_fb->angle);
+ st->fnr_report = l1s.current_time.fn;
+ st->attempt = attempt;
+
+ dump_mon_state(st);
+
+ dsp_api.ndb->d_fb_det = 0;
+ dsp_api.ndb->a_sync_demod[D_TOA] = 0; /* TSM30 does it (really needed ?) */
+
+ /* Update AFC with current frequency offset */
+ afc_correct(st->freq_diff, rf_arfcn);
+
+ //tpu_dsp_frameirq_enable();
+ return 1;
+}
+
+static void fbinfo2cellinfo(struct l1_cell_info *cinfo,
+ const struct mon_state *mon)
+{
+ int ntdma, qbits, fn_offset, fnr_delta, bits_delta;
+
+ /* FIXME: where did this magic 23 come from? */
+ last_fb->toa -= 23;
+
+ if (last_fb->toa < 0) {
+ qbits = (last_fb->toa + BITS_PER_TDMA) * 4;
+ ntdma = -1;
+ } else {
+ ntdma = (last_fb->toa) / BITS_PER_TDMA;
+ qbits = (last_fb->toa - ntdma * BITS_PER_TDMA) * 4;
+ }
+
+ fn_offset = l1s.current_time.fn - last_fb->attempt + ntdma;
+ fnr_delta = last_fb->fnr_report - last_fb->attempt;
+ bits_delta = fnr_delta * BITS_PER_TDMA;
+
+ cinfo->fn_offset = fnr_delta;
+ cinfo->time_alignment = qbits;
+ cinfo->arfcn = rf_arfcn;
+
+ if (last_fb->toa > bits_delta)
+ printf("=> DSP reports FB in bit that is %d bits in "
+ "the future?!?\n", last_fb->toa - bits_delta);
+ else {
+ int fb_fnr = (last_fb->fnr_report - last_fb->attempt)
+ + last_fb->toa/BITS_PER_TDMA;
+ printf("=>FB @ FNR %u fn_offset=%d qbits=%u\n",
+ fb_fnr, fn_offset, qbits);
+ }
+}
+
+/* scheduler callback to issue a FB detection task to the DSP */
+static int l1s_fbdet_cmd(__unused uint8_t p1, __unused uint8_t p2,
+ uint16_t fb_mode)
+{
+ if (fb_mode == 0) {
+ putchart('F');
+ } else {
+ putchart('V');
+ }
+
+ l1s.fb.mode = fb_mode;
+
+ /* Tell the RF frontend to set the gain appropriately */
+ rffe_compute_gain(-85, CAL_DSP_TGT_BB_LVL);
+
+ /* Program DSP */
+ dsp_api.db_w->d_task_md = FB_DSP_TASK; /* maybe with I/Q swap? */
+ dsp_api.ndb->d_fb_mode = fb_mode;
+
+ /* Program TPU */
+ l1s_rx_win_ctrl(fbs.req.band_arfcn, L1_RXWIN_FB, 0);
+
+ return 0;
+}
+
+#if 0
+#define FB0_SNR_THRESH 2000
+#define FB1_SNR_THRESH 3000
+#else
+#define FB0_SNR_THRESH 0
+#define FB1_SNR_THRESH 0
+#endif
+
+static const struct tdma_sched_item fb_sched_set[];
+
+/* scheduler callback to check for a FB detection response */
+static int l1s_fbdet_resp(__unused uint8_t p1, uint8_t attempt,
+ uint16_t fb_mode)
+{
+ putchart('f');
+
+ if (!dsp_api.ndb->d_fb_det) {
+ /* we did not detect a FB */
+
+ /* attempt < 12, do nothing */
+ if (attempt < 12)
+ return 0;
+
+ /* attempt >= 12, we simply don't find one */
+
+ /* If we don't reset here, we get DSP DMA errors */
+ tdma_sched_reset();
+
+ if (fbs.fb_retries < FB0_RETRY_COUNT) {
+ /* retry once more */
+ tdma_schedule_set(1, fb_sched_set, 0);
+ fbs.fb_retries++;
+ } else {
+ last_fb->attempt = 13;
+ l1s_compl_sched(L1_COMPL_FB);
+ }
+
+ return 0;
+ }
+
+ /* We found a frequency burst, reset everything */
+ l1s_reset_hw();
+
+ printf("FB%u ", dsp_api.ndb->d_fb_mode);
+ read_fb_result(last_fb, attempt);
+
+ /* if this is the first success, save freq err */
+ if (!fbs.initial_freq_err)
+ fbs.initial_freq_err = last_fb->freq_diff;
+
+ /* If we don't reset here, we get DSP DMA errors */
+ tdma_sched_reset();
+
+ /* Immediately schedule further TDMA tasklets, if requested. Doing
+ * this directly from L1S means we can do this quickly without any
+ * additional delays */
+ if (fb_mode == 0) {
+ if (fbs.req.flags & L1CTL_FBSB_F_FB1) {
+ /* If we don't reset here, we get DSP DMA errors */
+ tdma_sched_reset();
+ /* FIXME: don't only use the last but an average */
+ if (abs(last_fb->freq_diff) < fbs.req.freq_err_thresh1 &&
+ last_fb->snr > FB0_SNR_THRESH) {
+ /* continue with FB1 task in DSP */
+ tdma_schedule_set(1, fb_sched_set, 1);
+ } else {
+ if (fbs.afc_retries < AFC_RETRY_COUNT) {
+ tdma_schedule_set(1, fb_sched_set, 0);
+ fbs.afc_retries++;
+ } else {
+ /* Abort */
+ last_fb->attempt = 13;
+ l1s_compl_sched(L1_COMPL_FB);
+ }
+ }
+ } else
+ l1s_compl_sched(L1_COMPL_FB);
+ } else if (fb_mode == 1) {
+ if (fbs.req.flags & L1CTL_FBSB_F_SB) {
+
+ int ntdma, qbits;
+ /* FIXME: where did this magic 23 come from? */
+ last_fb->toa -= 23;
+
+ if (last_fb->toa < 0) {
+ qbits = (last_fb->toa + BITS_PER_TDMA) * 4;
+ ntdma = -1;
+ } else {
+ ntdma = (last_fb->toa) / BITS_PER_TDMA;
+ qbits = (last_fb->toa - ntdma * BITS_PER_TDMA) * 4;
+ }
+
+
+ int fn_offset = l1s.current_time.fn - last_fb->attempt + ntdma;
+ int delay = fn_offset + 11 - l1s.current_time.fn - 1;
+ printf(" fn_offset=%d (fn=%u + attempt=%u + ntdma = %d)\n",
+ fn_offset, l1s.current_time.fn, last_fb->attempt, ntdma);
+ printf(" delay=%d (fn_offset=%d + 11 - fn=%u - 1\n", delay,
+ fn_offset, l1s.current_time.fn);
+ printf(" scheduling next FB/SB detection task with delay %u\n", delay);
+ if (abs(last_fb->freq_diff) < fbs.req.freq_err_thresh2 &&
+ last_fb->snr > FB1_SNR_THRESH) {
+ /* synchronize before reading SB */
+ fbinfo2cellinfo(&l1s.serving_cell, last_fb);
+ synchronize_tdma(&l1s.serving_cell);
+ tdma_schedule_set(delay, sb_sched_set, 0);
+ } else
+ tdma_schedule_set(delay, fb_sched_set, 1);
+ } else
+ l1s_compl_sched(L1_COMPL_FB);
+ }
+
+ return 0;
+}
+
+/* FB detection */
+static const struct tdma_sched_item fb_sched_set[] = {
+ SCHED_ITEM_DT(l1s_fbdet_cmd, 0, 0, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 1), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 3), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 4), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 5), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 6), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 7), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 8), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 9), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 10), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 11), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, -4, 0, 12), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
+/* Asynchronous completion handler for FB detection */
+static void l1a_fb_compl(__unused enum l1_compl c)
+{
+ struct l1_cell_info *cinfo = &l1s.serving_cell;
+
+ if (last_fb->attempt >= 13) {
+ /* FB detection failed, signal this via L1CTL */
+ return l1ctl_fbsb_resp(255);
+ }
+
+ /* FIME: use l1s.neigh_cell[fbs.cinfo_idx] */
+ fbinfo2cellinfo(&l1s.serving_cell, last_fb);
+
+ /* send FBSB_CONF success message via L1CTL */
+ l1ctl_fbsb_resp(0);
+}
+
+void l1s_fbsb_req(uint8_t base_fn, struct l1ctl_fbsb_req *req)
+{
+ /* copy + endian convert request data */
+ fbs.req.band_arfcn = ntohs(req->band_arfcn);
+ fbs.req.timeout = ntohs(req->timeout);
+ fbs.req.freq_err_thresh1 = ntohs(req->freq_err_thresh1);
+ fbs.req.freq_err_thresh2 = ntohs(req->freq_err_thresh2);
+ fbs.req.num_freqerr_avg = req->num_freqerr_avg;
+ fbs.req.flags = req->flags;
+ fbs.req.sync_info_idx = req->sync_info_idx;
+
+ /* clear initial frequency error */
+ fbs.initial_freq_err = 0;
+ fbs.fb_retries = 0;
+ fbs.afc_retries = 0;
+
+ /* Make sure we start at a 'center' AFCDAC output value */
+ afc_reset();
+
+ /* Reset the TOA loop counters */
+ toa_reset();
+
+ if (fbs.req.flags & L1CTL_FBSB_F_FB0)
+ tdma_schedule_set(base_fn, fb_sched_set, 0);
+ else if (fbs.req.flags & L1CTL_FBSB_F_FB1)
+ tdma_schedule_set(base_fn, fb_sched_set, 0);
+ else if (fbs.req.flags & L1CTL_FBSB_F_SB)
+ tdma_schedule_set(base_fn, sb_sched_set, 0);
+
+}
+
+static __attribute__ ((constructor)) void l1s_prim_fbsb_init(void)
+{
+ l1s.completion[L1_COMPL_FB] = &l1a_fb_compl;
+}
diff --git a/src/target/firmware/layer1/prim_freq.c b/src/target/firmware/layer1/prim_freq.c
new file mode 100644
index 00000000..ca6dc9e4
--- /dev/null
+++ b/src/target/firmware/layer1/prim_freq.c
@@ -0,0 +1,113 @@
+/* Layer 1 Frequency redefinition at "starting time" */
+
+/* (C) 2010 by Andreas Eversverg <jolly@eversberg.eu>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+#include <asm/system.h>
+
+#include <layer1/sync.h>
+#include <layer1/async.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+#include <layer1/sched_gsmtime.h>
+
+#include <l1ctl_proto.h>
+
+struct {
+ uint32_t fn;
+ uint16_t band_arfcn;
+} last_rach;
+
+/* if the "starting time" is reached, use frequencies "after time" */
+static int l1s_freq_cmd(__unused uint8_t p1, __unused uint8_t p2, __unused uint16_t p3)
+{
+ putchart('F');
+
+ printf("Reached starting time, altering frequency set\n");
+
+ l1s.dedicated.tsc = l1s.dedicated.st_tsc;
+ l1s.dedicated.h = l1s.dedicated.st_h;
+ if (l1s.dedicated.h)
+ memcpy(&l1s.dedicated.h1, &l1s.dedicated.st_h1,
+ sizeof(l1s.dedicated.h1));
+ else
+ memcpy(&l1s.dedicated.h0, &l1s.dedicated.st_h0,
+ sizeof(l1s.dedicated.h0));
+
+ return 0;
+}
+
+/* sched set for frequency change */
+const struct tdma_sched_item freq_sched_set[] = {
+ SCHED_ITEM(l1s_freq_cmd, -3, 1, 0),
+ SCHED_END_SET()
+};
+
+/* request a frequency change at the given frame number
+ * Note: The fn_sched parameter must be in range 0..42431. */
+void l1a_freq_req(uint32_t fn_sched)
+{
+ int32_t diff;
+ unsigned long flags;
+
+ /* We must check here, if the time already elapsed.
+ * This is required, because we may have an undefined delay between
+ * layer 1 and layer 3.
+ */
+ diff = fn_sched - (l1s.current_time.fn % 42432);
+ if (diff < 0)
+ diff += 42432;
+ /* note: 5 is used to give scheduler some time */
+ if (diff == 5 || diff >= 32024) {
+ l1s_freq_cmd(0, 0, 0);
+ return;
+ }
+
+ /* calculate (full range) frame number */
+ fn_sched = l1s.current_time.fn + diff;
+ if (fn_sched >= GSM_MAX_FN)
+ fn_sched -= GSM_MAX_FN;
+ printf("Scheduling frequency change at fn=%u, currently fn=%u\n",
+ fn_sched, l1s.current_time.fn);
+
+ local_firq_save(flags);
+ sched_gsmtime(freq_sched_set, fn_sched, 0);
+ local_irq_restore(flags);
+}
+
diff --git a/src/target/firmware/layer1/prim_pm.c b/src/target/firmware/layer1/prim_pm.c
new file mode 100644
index 00000000..1630600a
--- /dev/null
+++ b/src/target/firmware/layer1/prim_pm.c
@@ -0,0 +1,241 @@
+/* Layer 1 Power Measurement */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+#include <asm/system.h>
+
+#include <layer1/sync.h>
+#include <layer1/agc.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+#include <layer1/prim.h>
+#include <rffe.h>
+
+#include <l1ctl_proto.h>
+
+static void l1ddsp_meas_read(uint8_t nbmeas, uint16_t *pm)
+{
+ uint8_t i;
+
+ for (i = 0; i < nbmeas; i++)
+ pm[i] = (uint16_t) ((dsp_api.db_r->a_pm[i] & 0xffff) >> 3);
+ dsp_api.r_page_used = 1;
+}
+
+/* scheduler callback to issue a power measurement task to the DSP */
+static int l1s_pm_cmd(uint8_t num_meas,
+ __unused uint8_t p2, uint16_t arfcn)
+{
+ putchart('P');
+
+ dsp_api.db_w->d_task_md = num_meas; /* number of measurements */
+ dsp_api.ndb->d_fb_mode = 0; /* wideband search */
+
+ /* Tell the RF frontend to set the gain appropriately */
+ rffe_compute_gain(-85, CAL_DSP_TGT_BB_LVL);
+
+ /* Program TPU */
+ /* FIXME: RXWIN_PW needs to set up multiple times in case
+ * num_meas > 1 */
+ l1s_rx_win_ctrl(arfcn, L1_RXWIN_PW, 0);
+ //l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB);
+
+ return 0;
+}
+
+/* scheduler callback to read power measurement resposnse from the DSP */
+static int l1s_pm_resp(uint8_t num_meas, __unused uint8_t p2,
+ uint16_t arfcn)
+{
+ struct l1ctl_pm_conf *pmr;
+ uint16_t pm_level[2];
+
+ putchart('p');
+
+ l1ddsp_meas_read(num_meas, pm_level);
+
+ printf("PM MEAS: ARFCN=%u, %-4d dBm at baseband, %-4d dBm at RF\n",
+ arfcn, pm_level[0]/8, agc_inp_dbm8_by_pm(pm_level[0])/8);
+
+ printd("PM MEAS: %-4d dBm, %-4d dBm ARFCN=%u\n",
+ agc_inp_dbm8_by_pm(pm_level[0])/8,
+ agc_inp_dbm8_by_pm(pm_level[1])/8, arfcn);
+
+ if (!l1s.pm.msg)
+ l1s.pm.msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
+
+ if (msgb_tailroom(l1s.pm.msg) < sizeof(*pmr)) {
+ /* flush current msgb */
+ l1_queue_for_l2(l1s.pm.msg);
+ /* allocate a new msgb and initialize header */
+ l1s.pm.msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
+ }
+
+ pmr = msgb_put(l1s.pm.msg, sizeof(*pmr));
+ pmr->band_arfcn = htons(arfcn);
+ /* FIXME: do this as RxLev rather than DBM8 ? */
+ pmr->pm[0] = dbm2rxlev(agc_inp_dbm8_by_pm(pm_level[0])/8);
+ if (num_meas > 1)
+ pmr->pm[1] = dbm2rxlev(agc_inp_dbm8_by_pm(pm_level[1])/8);
+ else
+ pmr->pm[1] = 0;
+
+ if (l1s.pm.mode == 1) {
+ if (l1s.pm.range.arfcn_next != l1s.pm.range.arfcn_end) {
+ /* schedule PM for next ARFCN in range */
+ l1s.pm.range.arfcn_next =
+ (l1s.pm.range.arfcn_next+1) & 0xfbff;
+ l1s_pm_test(1, l1s.pm.range.arfcn_next);
+ } else {
+ /* we have finished, flush the msgb to L2 */
+ struct l1ctl_hdr *l1h = l1s.pm.msg->l1h;
+ l1h->flags |= L1CTL_F_DONE;
+ l1_queue_for_l2(l1s.pm.msg);
+ l1s.pm.msg = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static const struct tdma_sched_item pm_sched_set[] = {
+ SCHED_ITEM_DT(l1s_pm_cmd, 0, 1, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_pm_resp, -4, 1, 0), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
+/* Schedule a power measurement test */
+void l1s_pm_test(uint8_t base_fn, uint16_t arfcn)
+{
+ unsigned long flags;
+
+ printd("l1s_pm_test(%u, %u)\n", base_fn, arfcn);
+
+ local_firq_save(flags);
+ tdma_schedule_set(base_fn, pm_sched_set, arfcn);
+ local_irq_restore(flags);
+}
+
+/*
+ * perform measurements of neighbour cells
+ */
+
+/* scheduler callback to issue a power measurement task to the DSP */
+static int l1s_neigh_pm_cmd(uint8_t num_meas,
+ __unused uint8_t p2, __unused uint16_t p3)
+{
+ uint8_t last_gain = rffe_get_gain();
+
+ dsp_api.db_w->d_task_md = num_meas; /* number of measurements */
+// dsp_api.ndb->d_fb_mode = 0; /* wideband search */
+
+ /* Tell the RF frontend to set the gain appropriately (keep last) */
+ rffe_compute_gain(-85, CAL_DSP_TGT_BB_LVL);
+
+ /* Program TPU */
+ /* FIXME: RXWIN_PW needs to set up multiple times in case
+ * num_meas > 1 */
+ /* do measurement dummy, in case l1s.neigh_pm.n == 0 */
+ l1s_rx_win_ctrl((l1s.neigh_pm.n) ?
+ l1s.neigh_pm.band_arfcn[l1s.neigh_pm.pos] : 0,
+ L1_RXWIN_PW, l1s.neigh_pm.tn[l1s.neigh_pm.pos]);
+
+ /* restore last gain */
+ rffe_set_gain(last_gain);
+
+ l1s.neigh_pm.running = 1;
+
+ return 0;
+}
+
+/* scheduler callback to read power measurement resposnse from the DSP */
+static int l1s_neigh_pm_resp(__unused uint8_t p1, __unused uint8_t p2,
+ __unused uint16_t p3)
+{
+ uint16_t dbm;
+ uint8_t level;
+
+ dsp_api.r_page_used = 1;
+
+ if (l1s.neigh_pm.n == 0 || !l1s.neigh_pm.running)
+ goto out;
+
+ dbm = (uint16_t) ((dsp_api.db_r->a_pm[0] & 0xffff) >> 3);
+ level = dbm2rxlev(agc_inp_dbm8_by_pm(dbm)/8);
+
+ l1s.neigh_pm.level[l1s.neigh_pm.pos] = level;
+
+ if (++l1s.neigh_pm.pos >= l1s.neigh_pm.n) {
+ struct msgb *msg;
+ struct l1ctl_neigh_pm_ind *mi;
+ int i;
+
+ l1s.neigh_pm.pos = 0;
+ /* return result */
+ msg = l1ctl_msgb_alloc(L1CTL_NEIGH_PM_IND);
+ for (i = 0; i < l1s.neigh_pm.n; i++) {
+ if (msgb_tailroom(msg) < (int) sizeof(*mi)) {
+ l1_queue_for_l2(msg);
+ msg = l1ctl_msgb_alloc(L1CTL_NEIGH_PM_IND);
+ }
+ mi = (struct l1ctl_neigh_pm_ind *)
+ msgb_put(msg, sizeof(*mi));
+ mi->band_arfcn = htons(l1s.neigh_pm.band_arfcn[i]);
+ mi->tn = l1s.neigh_pm.tn[i];
+ mi->pm[0] = l1s.neigh_pm.level[i];
+ mi->pm[1] = 0;
+ }
+ l1_queue_for_l2(msg);
+ }
+
+out:
+ l1s.neigh_pm.running = 0;
+
+ return 0;
+}
+
+const struct tdma_sched_item neigh_pm_sched_set[] = {
+ SCHED_ITEM_DT(l1s_neigh_pm_cmd, 0, 1, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_neigh_pm_resp, -4, 1, 0), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
diff --git a/src/target/firmware/layer1/prim_rach.c b/src/target/firmware/layer1/prim_rach.c
new file mode 100644
index 00000000..27e89abb
--- /dev/null
+++ b/src/target/firmware/layer1/prim_rach.c
@@ -0,0 +1,160 @@
+/* Layer 1 Random Access Channel Burst */
+
+/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+#include <asm/system.h>
+
+#include <layer1/sync.h>
+#include <layer1/async.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+#include <layer1/sched_gsmtime.h>
+
+#include <l1ctl_proto.h>
+
+struct {
+ uint32_t fn;
+ uint16_t band_arfcn;
+} last_rach;
+
+/* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB */
+static int l1s_tx_rach_cmd(__unused uint8_t p1, __unused uint8_t p2, __unused uint16_t p3)
+{
+ int i;
+ uint16_t *info_ptr;
+ uint8_t data[2];
+
+ putchart('T');
+
+ l1s_tx_apc_helper(l1s.serving_cell.arfcn);
+
+ data[0] = l1s.serving_cell.bsic << 2;
+ data[1] = l1s.rach.ra;
+
+ info_ptr = &dsp_api.ndb->d_rach;
+ info_ptr[0] = ((uint16_t)(data[0])) | ((uint16_t)(data[1])<<8);
+
+ dsp_api.db_w->d_task_ra = RACH_DSP_TASK;
+
+ l1s_tx_win_ctrl(l1s.serving_cell.arfcn | ARFCN_UPLINK, L1_TXWIN_AB, 0, 3);
+
+ return 0;
+}
+
+/* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB */
+static int l1s_tx_rach_resp(__unused uint8_t p1, __unused uint8_t burst_id,
+ __unused uint16_t p3)
+{
+ putchart('t');
+
+ dsp_api.r_page_used = 1;
+
+ /* schedule a confirmation back indicating the GSM time at which
+ * the RACH burst was transmitted to the BTS */
+ last_rach.fn = l1s.current_time.fn - 1;
+ last_rach.band_arfcn = l1s.serving_cell.arfcn;
+ l1s_compl_sched(L1_COMPL_RACH);
+
+ return 0;
+}
+
+/* sched sets for uplink */
+const struct tdma_sched_item rach_sched_set_ul[] = {
+ SCHED_ITEM_DT(l1s_tx_rach_cmd, 3, 1, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_tx_rach_resp, -4, 1, 0), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
+/* Asynchronous completion handler for FB detection */
+static void l1a_rach_compl(__unused enum l1_compl c)
+{
+ struct msgb *msg;
+
+ msg = l1_create_l2_msg(L1CTL_RACH_CONF, last_rach.fn, 0,
+ last_rach.band_arfcn);
+ l1_queue_for_l2(msg);
+}
+
+static uint8_t t3_to_rach_comb[51] = {
+ 0, 0, 0, 0,
+ 0, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 26,
+ 27, 27, 27, 27};
+static uint8_t rach_to_t3_comb[27] = {
+ 4, 5,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 45, 46};
+
+/* request a RACH request at the next multiframe T3 = fn51 */
+void l1a_rach_req(uint16_t offset, uint8_t combined, uint8_t ra)
+{
+ uint32_t fn_sched;
+ unsigned long flags;
+
+ offset += 3;
+
+ local_firq_save(flags);
+ if (combined) {
+ /* add elapsed RACH slots to offset */
+ offset += t3_to_rach_comb[l1s.current_time.t3];
+ /* offset is the number of RACH slots in the future */
+ fn_sched = l1s.current_time.fn - l1s.current_time.t3;
+ fn_sched += offset / 27 * 51;
+ fn_sched += rach_to_t3_comb[offset % 27];
+ } else
+ fn_sched = l1s.current_time.fn + offset;
+ l1s.rach.ra = ra;
+ sched_gsmtime(rach_sched_set_ul, fn_sched, 0);
+ local_irq_restore(flags);
+
+ memset(&last_rach, 0, sizeof(last_rach));
+}
+
+static __attribute__ ((constructor)) void prim_rach_init(void)
+{
+ l1s.completion[L1_COMPL_RACH] = &l1a_rach_compl;
+}
diff --git a/src/target/firmware/layer1/prim_rx_nb.c b/src/target/firmware/layer1/prim_rx_nb.c
new file mode 100644
index 00000000..ade23a01
--- /dev/null
+++ b/src/target/firmware/layer1/prim_rx_nb.c
@@ -0,0 +1,217 @@
+/* Layer 1 - Receiving Normal Bursts */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <rffe.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+
+#include <layer1/sync.h>
+#include <layer1/afc.h>
+#include <layer1/toa.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/mframe_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+#include <layer1/rfch.h>
+#include <layer1/prim.h>
+#include <layer1/agc.h>
+
+#include <l1ctl_proto.h>
+
+struct l1s_rxnb_state {
+ struct l1s_meas_hdr meas[4];
+
+ struct msgb *msg;
+ struct l1ctl_info_dl *dl;
+ struct l1ctl_data_ind *di;
+};
+
+static struct l1s_rxnb_state rxnb;
+
+static int l1s_nb_resp(__unused uint8_t p1, uint8_t burst_id, uint16_t p3)
+{
+ struct gsm_time rx_time;
+ uint8_t mf_task_id = p3 & 0xff;
+ uint8_t mf_task_flags = p3 >> 8;
+ uint16_t rf_arfcn;
+ uint8_t tsc, tn;
+
+ putchart('n');
+
+ /* just for debugging, d_task_d should not be 0 */
+ if (dsp_api.db_r->d_task_d == 0) {
+ puts("EMPTY\n");
+ return 0;
+ }
+
+ /* DSP burst ID needs to correspond with what we expect */
+ if (dsp_api.db_r->d_burst_d != burst_id) {
+ printf("BURST ID %u!=%u\n", dsp_api.db_r->d_burst_d, burst_id);
+ return 0;
+ }
+
+ /* get radio parameters for _this_ burst */
+ gsm_fn2gsmtime(&rx_time, l1s.current_time.fn - 1);
+ rfch_get_params(&rx_time, &rf_arfcn, &tsc, &tn);
+
+ /* collect measurements */
+ rxnb.meas[burst_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
+ rxnb.meas[burst_id].pm_dbm8 =
+ agc_inp_dbm8_by_pm(dsp_api.db_r->a_serv_demod[D_PM] >> 3);
+ rxnb.meas[burst_id].freq_err =
+ ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
+ rxnb.meas[burst_id].snr = dsp_api.db_r->a_serv_demod[D_SNR];
+
+ /* feed computed frequency error into AFC loop */
+ if (rxnb.meas[burst_id].snr > AFC_SNR_THRESHOLD)
+ afc_input(rxnb.meas[burst_id].freq_err, rf_arfcn, 1);
+ else
+ afc_input(rxnb.meas[burst_id].freq_err, rf_arfcn, 0);
+
+ /* feed computed TOA into TA loop */
+ toa_input(rxnb.meas[burst_id].toa_qbit << 2, rxnb.meas[burst_id].snr);
+
+ /* Tell the RF frontend to set the gain appropriately */
+ rffe_compute_gain(rxnb.meas[burst_id].pm_dbm8/8, CAL_DSP_TGT_BB_LVL);
+
+ /* 4th burst, get frame data */
+ if (dsp_api.db_r->d_burst_d == 3) {
+ uint8_t i;
+ uint16_t num_biterr;
+ uint32_t avg_snr = 0;
+ int32_t avg_dbm8 = 0;
+
+ /* Get radio parameters for the first burst */
+ gsm_fn2gsmtime(&rx_time, l1s.current_time.fn - 4);
+ rfch_get_params(&rx_time, &rf_arfcn, &tsc, &tn);
+
+ /* Set Channel Number depending on MFrame Task ID */
+ rxnb.dl->chan_nr = mframe_task2chan_nr(mf_task_id, tn);
+
+ /* Set SACCH indication in Link IDentifier */
+ if (mf_task_flags & MF_F_SACCH)
+ rxnb.dl->link_id = 0x40;
+ else
+ rxnb.dl->link_id = 0x00;
+
+ rxnb.dl->band_arfcn = htons(rf_arfcn);
+
+ rxnb.dl->frame_nr = htonl(rx_time.fn);
+
+ /* compute average snr and rx level */
+ for (i = 0; i < 4; ++i) {
+ avg_snr += rxnb.meas[i].snr;
+ avg_dbm8 += rxnb.meas[i].pm_dbm8;
+ }
+ rxnb.dl->snr = avg_snr / 4;
+ rxnb.dl->rx_level = dbm2rxlev(avg_dbm8 / (8*4));
+
+ num_biterr = dsp_api.ndb->a_cd[2] & 0xffff;
+ if (num_biterr > 0xff)
+ rxnb.dl->num_biterr = 0xff;
+ else
+ rxnb.dl->num_biterr = num_biterr;
+
+ rxnb.dl->fire_crc = ((dsp_api.ndb->a_cd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
+
+ /* update rx level for pm report */
+ pu_update_rx_level(rxnb.dl->rx_level);
+
+ /* copy actual data, skipping the information block [0,1,2] */
+ dsp_memcpy_from_api(rxnb.di->data, &dsp_api.ndb->a_cd[3], 23, 0);
+
+ l1_queue_for_l2(rxnb.msg);
+ rxnb.msg = NULL; rxnb.dl = NULL; rxnb.di = NULL;
+
+ /* clear downlink task */
+ dsp_api.db_w->d_task_d = 0;
+ }
+
+ /* mark READ page as being used */
+ dsp_api.r_page_used = 1;
+
+ return 0;
+}
+
+static int l1s_nb_cmd(__unused uint8_t p1, uint8_t burst_id,
+ __unused uint16_t p3)
+{
+ uint16_t arfcn;
+ uint8_t tsc, tn;
+
+ putchart('N');
+
+ if (burst_id == 1) {
+ /* allocate message only at 2nd burst in case of
+ * consecutive/overlapping normal burst RX tasks */
+ /* FIXME: we actually want all allocation out of L1S! */
+ if (rxnb.msg) {
+ /* Can happen when resetting ... */
+ printf("nb_cmd(0) and rxnb.msg != NULL\n");
+ msgb_free(rxnb.msg);
+ }
+ /* allocate msgb as needed. FIXME: from L1A ?? */
+ rxnb.msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
+ if (!rxnb.msg)
+ printf("nb_cmd(0): unable to allocate msgb\n");
+ rxnb.dl = (struct l1ctl_info_dl *) msgb_put(rxnb.msg, sizeof(*rxnb.dl));
+ rxnb.di = (struct l1ctl_data_ind *) msgb_put(rxnb.msg, sizeof(*rxnb.di));
+ }
+
+ rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
+
+ /* DDL_DSP_TASK, four normal bursts */
+ dsp_load_tch_param(&l1s.next_time,
+ SIG_ONLY_MODE, SDCCH_4, 0, 0, 0, tn);
+
+ dsp_load_rx_task(ALLC_DSP_TASK, burst_id, tsc);
+
+ l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
+
+ return 0;
+}
+
+const struct tdma_sched_item nb_sched_set[] = {
+ SCHED_ITEM_DT(l1s_nb_cmd, 0, 0, 0), SCHED_END_FRAME(),
+ SCHED_ITEM_DT(l1s_nb_cmd, 0, 0, 1), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_resp, -4, 0, 0), SCHED_ITEM_DT(l1s_nb_cmd, 0, 0, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_resp, -4, 0, 1), SCHED_ITEM_DT(l1s_nb_cmd, 0, 0, 3), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_resp, -4, 0, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_resp, -4, 0, 3), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
diff --git a/src/target/firmware/layer1/prim_tch.c b/src/target/firmware/layer1/prim_tch.c
new file mode 100644
index 00000000..a26c58ea
--- /dev/null
+++ b/src/target/firmware/layer1/prim_tch.c
@@ -0,0 +1,752 @@
+/* Layer 1 - TCH */
+
+/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
+ * (C) 2010 by Sylvain Munaut <tnt@246tnt.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/core/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+
+#include <rffe.h>
+#include <layer1/sync.h>
+#include <layer1/afc.h>
+#include <layer1/agc.h>
+#include <layer1/toa.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/mframe_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+#include <layer1/rfch.h>
+#include <layer1/prim.h>
+
+#include <l1ctl_proto.h>
+
+
+/* This computes various parameters both for the DSP and for
+ * our logic. Not all are used all the time, but it's easier
+ * to build all in one place */
+static void tch_get_params(struct gsm_time *time, uint8_t chan_nr,
+ uint32_t *fn_report, uint8_t *tch_f_hn,
+ uint8_t *tch_sub, uint8_t *tch_mode)
+{
+ uint8_t tn = chan_nr & 0x07;
+ uint8_t cbits = chan_nr >> 3;
+
+ *tch_f_hn = (cbits & 2) ? 0 : 1;
+
+ if (*tch_f_hn) {
+ *fn_report = (time->fn - (tn * 13) + 104) % 104;
+ *tch_sub = 0;
+ } else {
+ uint8_t chan_sub = cbits & 1;
+ uint8_t tn_report = (tn & ~1) | chan_sub;
+ *fn_report = (time->fn - (tn_report * 13) + 104) % 104;
+ *tch_sub = chan_sub;
+ }
+
+ if (tch_mode) {
+ switch (l1s.tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ *tch_mode = *tch_f_hn ? TCH_FS_MODE : TCH_HS_MODE;
+ break;
+ case GSM48_CMODE_SPEECH_EFR:
+ *tch_mode = *tch_f_hn ? TCH_EFR_MODE : SIG_ONLY_MODE;
+ break;
+ default:
+ *tch_mode = SIG_ONLY_MODE;
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------
+ * Shared completion handler
+ * ------------------------------------------------------------------------- */
+
+/*
+ * FIXME We really need a better way to handle completion, where we can
+ * pass arguments and such ...
+ *
+ * Right now, we just 'hope' it gets processed before the next one ...
+ */
+
+#define TX_TYPE_SACCH (1<<0)
+#define TX_TYPE_FACCH (1<<1)
+#define TX_TYPE_TRAFFIC (1<<2)
+
+static uint16_t last_tx_tch_fn;
+static uint16_t last_tx_tch_type;
+
+static void l1a_tx_tch_compl(__unused enum l1_compl c)
+{
+ struct msgb *msg;
+
+ if (last_tx_tch_type & (TX_TYPE_SACCH | TX_TYPE_FACCH)) {
+ msg = l1_create_l2_msg(L1CTL_DATA_CONF, last_tx_tch_fn, 0, 0);
+ l1_queue_for_l2(msg);
+ }
+
+ if (last_tx_tch_type & TX_TYPE_TRAFFIC) {
+ msg = l1_create_l2_msg(L1CTL_TRAFFIC_CONF, last_tx_tch_fn, 0, 0);
+ l1_queue_for_l2(msg);
+ }
+
+ last_tx_tch_type = 0;
+}
+
+static __attribute__ ((constructor)) void prim_tch_init(void)
+{
+ l1s.completion[L1_COMPL_TX_TCH] = &l1a_tx_tch_compl;
+}
+
+
+/* -------------------------------------------------------------------------
+ * TCH: Voice & FACCH
+ * ------------------------------------------------------------------------- */
+
+/*
+ * Voice and FACCH data are spread in various ways depending on a lot of
+ * factors. Trying to handle that with the mframe scheduler is just a mess,
+ * so we schedule it burst by burst and handle the complex logic inside the
+ * primitive task code itself.
+ */
+
+
+#define FACCH_MEAS_HIST 8 /* Up to 8 bursts history */
+struct l1s_rx_tch_state {
+ struct l1s_meas_hdr meas[FACCH_MEAS_HIST];
+};
+
+static struct l1s_rx_tch_state rx_tch;
+
+
+static int l1s_tch_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
+{
+ static uint8_t meas_id = 0;
+ uint8_t mf_task_id = p3 & 0xff;
+ struct gsm_time rx_time;
+ uint8_t chan_nr;
+ uint16_t arfcn;
+ uint8_t tsc, tn;
+ uint8_t tch_f_hn, tch_sub;
+ uint32_t fn_report;
+ int facch_rx_now, traffic_rx_now;
+
+ /* Get/compute various parameters */
+ gsm_fn2gsmtime(&rx_time, (l1s.current_time.fn - 1 + GSM_MAX_FN) % GSM_MAX_FN);
+ rfch_get_params(&rx_time, &arfcn, &tsc, &tn);
+ chan_nr = mframe_task2chan_nr(mf_task_id, tn);
+ tch_get_params(&rx_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, NULL);
+
+ meas_id = (meas_id + 1) % FACCH_MEAS_HIST; /* absolute value doesn't matter */
+
+ /* Collect measurements */
+ rx_tch.meas[meas_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
+ rx_tch.meas[meas_id].pm_dbm8 =
+ agc_inp_dbm8_by_pm(dsp_api.db_r->a_serv_demod[D_PM] >> 3);
+ rx_tch.meas[meas_id].freq_err =
+ ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
+ rx_tch.meas[meas_id].snr = dsp_api.db_r->a_serv_demod[D_SNR];
+
+ /* feed computed frequency error into AFC loop */
+ if (rx_tch.meas[meas_id].snr > AFC_SNR_THRESHOLD)
+ afc_input(rx_tch.meas[meas_id].freq_err, arfcn, 1);
+ else
+ afc_input(rx_tch.meas[meas_id].freq_err, arfcn, 0);
+
+ /* feed computed TOA into TA loop */
+ toa_input(rx_tch.meas[meas_id].toa_qbit << 2, rx_tch.meas[meas_id].snr);
+
+ /* Tell the RF frontend to set the gain appropriately */
+ rffe_compute_gain(rx_tch.meas[meas_id].pm_dbm8 / 8,
+ CAL_DSP_TGT_BB_LVL);
+
+ /* FACCH Block end ? */
+ if (tch_f_hn) {
+ /* FACCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) (mod 13) */
+ facch_rx_now = ((rx_time.fn % 13) % 4) == 3;
+ } else {
+ /* FAACH/H: See GSM 05.02 Clause 7 Table 1of9 */
+ uint8_t t2_norm = rx_time.t2 - tch_sub;
+ facch_rx_now = (t2_norm == 15) ||
+ (t2_norm == 23) ||
+ (t2_norm == 6);
+ }
+
+ if (facch_rx_now && (dsp_api.ndb->a_fd[0] & (1<<B_BLUD))) {
+ struct msgb *msg;
+ struct l1ctl_info_dl *dl;
+ struct l1ctl_data_ind *di;
+ uint16_t num_biterr;
+ uint32_t avg_snr = 0;
+ int32_t avg_dbm8 = 0;
+ int i, n;
+
+ /* Allocate msgb */
+ /* FIXME: we actually want all allocation out of L1S! */
+ msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
+ if(!msg) {
+ printf("TCH FACCH: unable to allocate msgb\n");
+ goto skip_rx_facch;
+ }
+
+ dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
+ di = (struct l1ctl_data_ind *) msgb_put(msg, sizeof(*di));
+
+ /* Fill DL header (should be about the first burst ... here is the last) */
+ dl->chan_nr = chan_nr;
+ dl->link_id = 0x00; /* FACCH */
+ dl->band_arfcn = htons(arfcn);
+ dl->frame_nr = htonl(rx_time.fn);
+
+ /* Average SNR & RX level */
+ n = tch_f_hn ? 8 : 6;
+ for (i=0; i<n; i++) {
+ int j = (meas_id + FACCH_MEAS_HIST - i) % FACCH_MEAS_HIST;
+ avg_snr += rx_tch.meas[j].snr;
+ avg_dbm8 += rx_tch.meas[j].pm_dbm8;
+ }
+
+ dl->snr = avg_snr / n;
+ dl->rx_level = dbm2rxlev(avg_dbm8 / (8*n));
+
+ /* Errors & CRC status */
+ num_biterr = dsp_api.ndb->a_fd[2] & 0xffff;
+ if (num_biterr > 0xff)
+ dl->num_biterr = 0xff;
+ else
+ dl->num_biterr = num_biterr;
+
+ dl->fire_crc = ((dsp_api.ndb->a_fd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
+
+ /* Update rx level for pm report */
+ pu_update_rx_level(dl->rx_level);
+
+ /* Copy actual data, skipping the information block [0,1,2] */
+ dsp_memcpy_from_api(di->data, &dsp_api.ndb->a_fd[3], 23, 0);
+
+ /* Give message to up layer */
+ l1_queue_for_l2(msg);
+
+ skip_rx_facch:
+ /* Reset A_FD header (needed by DSP) */
+ /* B_FIRE1 =1, B_FIRE0 =0 , BLUD =0 */
+ dsp_api.ndb->a_fd[0] = (1<<B_FIRE1);
+ dsp_api.ndb->a_fd[2] = 0xffff;
+
+ /* Reset A_DD_0 header in NDB (needed by DSP) */
+ dsp_api.ndb->a_dd_0[0] = 0;
+ dsp_api.ndb->a_dd_0[2] = 0xffff;
+
+ /* Reset A_DD_1 header in NDB (needed by DSP) */
+ dsp_api.ndb->a_dd_1[0] = 0;
+ dsp_api.ndb->a_dd_1[2] = 0xffff;
+ }
+
+ /* Traffic now ? */
+ if (tch_f_hn) {
+ /* TCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) (mod 13)*/
+ traffic_rx_now = ((rx_time.fn % 13) % 4) == 3;
+ } else {
+ /* TCH/H0: B0(0,2,4,6),B1(4,6,8,10),B2(8,10,0,2) (mod 13) */
+ /* H1: B0(1,3,5,7),B1(5,7,9,11),B2(9,11,1,3) (mod 13) */
+ traffic_rx_now = (((rx_time.fn - tch_sub + 13) % 13) % 4) == 2;
+ }
+
+ if (traffic_rx_now) {
+ volatile uint16_t *traffic_buf;
+
+ traffic_buf = tch_sub ? dsp_api.ndb->a_dd_1 : dsp_api.ndb->a_dd_0;
+
+ if (traffic_buf[0] & (1<<B_BLUD)) {
+ /* Send the data to upper layers (if interested and good frame) */
+ if ((l1s.audio_mode & AUDIO_RX_TRAFFIC_IND) &&
+ !(dsp_api.ndb->a_dd_0[0] & (1<<B_BFI))) {
+ struct msgb *msg;
+ struct l1ctl_info_dl *dl;
+ struct l1ctl_traffic_ind *ti;
+
+ /* Allocate msgb */
+ /* FIXME: we actually want all allocation out of L1S! */
+ msg = l1ctl_msgb_alloc(L1CTL_TRAFFIC_IND);
+ if(!msg) {
+ printf("TCH traffic: unable to allocate msgb\n");
+ goto skip_rx_traffic;
+ }
+
+ dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
+ ti = (struct l1ctl_traffic_ind *) msgb_put(msg, sizeof(*ti));
+
+ /* Copy actual data, skipping the information block [0,1,2] */
+ dsp_memcpy_from_api(ti->data, &traffic_buf[3], 33, 1);
+
+ /* Give message to up layer */
+ l1_queue_for_l2(msg);
+ }
+
+ skip_rx_traffic:
+ /* Reset traffic buffer header in NDB (needed by DSP) */
+ traffic_buf[0] = 0;
+ traffic_buf[2] = 0xffff;
+ }
+ }
+
+ /* mark READ page as being used */
+ dsp_api.r_page_used = 1;
+
+ return 0;
+}
+
+static int l1s_tch_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
+{
+ uint8_t mf_task_id = p3 & 0xff;
+ uint8_t chan_nr;
+ uint16_t arfcn;
+ uint8_t tsc, tn;
+ uint8_t tch_f_hn, tch_sub, tch_mode;
+ uint32_t fn_report;
+ uint8_t sync = 0;
+ static int icnt;
+ int facch_tx_now, traffic_tx_now;
+
+ /* Get/compute various parameters */
+ rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
+ chan_nr = mframe_task2chan_nr(mf_task_id, tn);
+ tch_get_params(&l1s.next_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, &tch_mode);
+
+ /* Sync & FACCH delay */
+ if (l1s.tch_sync) {
+ l1s.tch_sync = 0;
+ sync = 1;
+ icnt = 0;
+ } else if (icnt <= 26)
+ icnt++;
+
+ /* Load FACCH data if we start a new burst */
+ /* (the DSP wants the data on the CMD of the burst _preceding_ the
+ * first burst) */
+ if (tch_f_hn) {
+ /* FACCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) */
+ facch_tx_now = ((l1s.next_time.fn % 13) % 4) == 3;
+ } else {
+ /* FAACH/H: See GSM 05.02 Clause 7 Table 1of9 */
+ uint8_t t2_norm = l1s.next_time.t2 - tch_sub;
+ facch_tx_now = (t2_norm == 23) ||
+ (t2_norm == 6) ||
+ (t2_norm == 15);
+ }
+
+ if (facch_tx_now) {
+ uint16_t *info_ptr = dsp_api.ndb->a_fu;
+ struct msgb *msg;
+ const uint8_t *data;
+
+ /* Pull FACCH data (if ready) */
+ if (icnt > 26)
+ msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_MAIN]);
+ else
+ msg = NULL;
+
+ /* If TX is empty and we're signalling only, use dummy frame */
+ if (msg)
+ data = msg->l3h;
+ else if (tch_mode == SIG_ONLY_MODE)
+ data = pu_get_idle_frame();
+ else
+ data = NULL;
+
+ /* Do we really send something ? */
+ if (data) {
+ /* Fill data block header */
+ info_ptr[0] = (1 << B_BLUD); /* 1st word: Set B_BLU bit. */
+ info_ptr[1] = 0; /* 2nd word: cleared. */
+ info_ptr[2] = 0; /* 3nd word: cleared. */
+
+ /* Copy the actual data after the header */
+ dsp_memcpy_to_api(&info_ptr[3], data, 23, 0);
+ }
+
+ /* Indicate completion (FIXME: early but easier this way for now) */
+ if (msg) {
+ last_tx_tch_fn = l1s.next_time.fn;
+ last_tx_tch_type |= TX_TYPE_FACCH;
+ l1s_compl_sched(L1_COMPL_TX_TCH);
+ }
+
+ /* Free msg now that we're done with it */
+ if (msg)
+ msgb_free(msg);
+ }
+
+ /* Traffic now ? */
+ if (tch_f_hn) {
+ /* TCH/F: B0(0...7),B1(4...11),B2(8...11,0...3) (mod 13)*/
+ traffic_tx_now = ((l1s.next_time.fn % 13) % 4) == 3;
+ } else {
+ /* TCH/H0: B0(0,2,4,6),B1(4,6,8,10),B2(8,10,0,2) (mod 13) */
+ /* H1: B0(1,3,5,7),B1(5,7,9,11),B2(9,11,1,3) (mod 13) */
+ traffic_tx_now = (((l1s.next_time.fn - tch_sub + 13) % 13) % 4) == 2;
+ }
+
+ if (traffic_tx_now) {
+ volatile uint16_t *traffic_buf;
+ struct msgb *msg;
+ const uint8_t *data;
+
+ /* Reset play mode */
+ dsp_api.ndb->d_tch_mode &= ~B_PLAY_UL;
+
+ /* Check l1s audio mode */
+ if (!(l1s.audio_mode & AUDIO_TX_TRAFFIC_REQ))
+ goto skip_tx_traffic;
+
+ /* Traffic buffer = !tch_sub */
+ traffic_buf = tch_sub ? dsp_api.ndb->a_du_0 : dsp_api.ndb->a_du_1;
+
+ /* Pull Traffic data (if any) */
+ msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_TRAFFIC]);
+
+ /* Copy actual data, skipping the information block [0,1,2] */
+ if (msg) {
+ data = msg->l2h;
+ dsp_memcpy_to_api(&traffic_buf[3], data, 33, 1);
+
+ traffic_buf[0] = (1 << B_BLUD); /* 1st word: Set B_BLU bit. */
+ traffic_buf[1] = 0; /* 2nd word: cleared. */
+ traffic_buf[2] = 0; /* 3nd word: cleared. */
+ }
+
+ if (msg)
+ dsp_api.ndb->d_tch_mode |= B_PLAY_UL;
+
+ /* Indicate completion (FIXME: early but easier this way for now) */
+ if (msg) {
+ last_tx_tch_fn = l1s.next_time.fn;
+ last_tx_tch_type |= TX_TYPE_TRAFFIC;
+ l1s_compl_sched(L1_COMPL_TX_TCH);
+ }
+
+ /* Free msg now that we're done with it */
+ if (msg)
+ msgb_free(msg);
+ }
+skip_tx_traffic:
+
+ /* Configure DSP for TX/RX */
+ l1s_tx_apc_helper(arfcn);
+
+ dsp_load_tch_param(
+ &l1s.next_time,
+ tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
+ 0, sync, tn
+ );
+
+ dsp_load_rx_task(TCHT_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
+ l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
+
+ dsp_load_tx_task(TCHT_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
+ l1s_tx_win_ctrl(arfcn | ARFCN_UPLINK, L1_TXWIN_NB, 0, 3);
+
+ return 0;
+}
+
+
+const struct tdma_sched_item tch_sched_set[] = {
+ SCHED_ITEM_DT(l1s_tch_cmd, 0, 0, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_tch_resp, 0, 0, -4), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
+
+/* -------------------------------------------------------------------------
+ * TCH/H: Dummy
+ * ------------------------------------------------------------------------- */
+
+/* This task is needed to perform some operation in the DSP when there is
+ * no data to be exchanged */
+
+static int l1s_tch_d_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
+{
+ /* mark READ page as being used */
+ dsp_api.r_page_used = 1;
+
+ return 0;
+}
+
+static int l1s_tch_d_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
+{
+ uint8_t mf_task_id = p3 & 0xff;
+ uint8_t chan_nr;
+ uint8_t tsc, tn;
+ uint8_t tch_f_hn, tch_sub, tch_mode;
+ uint32_t fn_report;
+
+ /* Get/compute various parameters */
+ rfch_get_params(&l1s.next_time, NULL, &tsc, &tn);
+ chan_nr = mframe_task2chan_nr(mf_task_id, tn);
+ tch_get_params(&l1s.next_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, &tch_mode);
+
+ /* Configure DSP */
+ dsp_load_tch_param(
+ &l1s.next_time,
+ tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
+ 0, 0, tn
+ );
+
+ dsp_load_rx_task(TCHD_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
+ dsp_load_tx_task(TCHD_DSP_TASK, 0, tsc); /* burst_id unused for TCH */
+
+ return 0;
+}
+
+const struct tdma_sched_item tch_d_sched_set[] = {
+ SCHED_ITEM_DT(l1s_tch_d_cmd, 0, 0, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_tch_d_resp, 0, 0, -4), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
+
+/* -------------------------------------------------------------------------
+ * TCH: SACCH
+ * ------------------------------------------------------------------------- */
+
+/*
+ * SACCH data are spread over 4 bursts, however they are so far appart that
+ * we can't use the normal scheduler to schedule all them at once in a single
+ * set.
+ * Therefore, the task code itself decides in which burst it is, if it's the
+ * start/end, and act appropriately.
+ */
+
+
+struct l1s_rx_tch_a_state {
+ struct l1s_meas_hdr meas[4];
+
+ struct msgb *msg;
+ struct l1ctl_info_dl *dl;
+ struct l1ctl_data_ind *di;
+};
+
+static struct l1s_rx_tch_a_state rx_tch_a;
+
+
+static int l1s_tch_a_resp(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
+{
+ uint8_t mf_task_id = p3 & 0xff;
+ struct gsm_time rx_time;
+ uint8_t chan_nr;
+ uint16_t arfcn;
+ uint8_t tsc, tn;
+ uint8_t tch_f_hn, tch_sub;
+ uint32_t fn_report;
+ uint8_t burst_id;
+
+ /* It may happen we've never gone through cmd(0) yet, skip until then */
+ if (!rx_tch_a.msg)
+ goto skip;
+
+ /* Get/compute various parameters */
+ gsm_fn2gsmtime(&rx_time, (l1s.current_time.fn - 1 + GSM_MAX_FN) % GSM_MAX_FN);
+ rfch_get_params(&rx_time, &arfcn, &tsc, &tn);
+ chan_nr = mframe_task2chan_nr(mf_task_id, tn);
+ tch_get_params(&rx_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, NULL);
+ burst_id = (fn_report - 12) / 26;
+
+ /* Collect measurements */
+ rx_tch_a.meas[burst_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
+ rx_tch_a.meas[burst_id].pm_dbm8 =
+ agc_inp_dbm8_by_pm(dsp_api.db_r->a_serv_demod[D_PM] >> 3);
+ rx_tch_a.meas[burst_id].freq_err =
+ ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
+ rx_tch_a.meas[burst_id].snr = dsp_api.db_r->a_serv_demod[D_SNR];
+
+ /* feed computed frequency error into AFC loop */
+ if (rx_tch_a.meas[burst_id].snr > AFC_SNR_THRESHOLD)
+ afc_input(rx_tch_a.meas[burst_id].freq_err, arfcn, 1);
+ else
+ afc_input(rx_tch_a.meas[burst_id].freq_err, arfcn, 0);
+
+ /* feed computed TOA into TA loop */
+ toa_input(rx_tch_a.meas[burst_id].toa_qbit << 2, rx_tch_a.meas[burst_id].snr);
+
+ /* Tell the RF frontend to set the gain appropriately */
+ rffe_compute_gain(rx_tch_a.meas[burst_id].pm_dbm8 / 8,
+ CAL_DSP_TGT_BB_LVL);
+
+ /* Last burst, read data & send to the up layer */
+ if ((burst_id == 3) && (dsp_api.ndb->a_cd[0] & (1<<B_BLUD))) {
+ unsigned int i;
+ uint16_t num_biterr;
+ uint32_t avg_snr = 0;
+ int32_t avg_dbm8 = 0;
+
+ /* Average SNR & RX level + error & crc status */
+ for (i=0; i<4; i++) {
+ avg_snr += rx_tch_a.meas[i].snr;
+ avg_dbm8 += rx_tch_a.meas[i].pm_dbm8;
+ }
+ rx_tch_a.dl->snr = avg_snr / 4;
+ rx_tch_a.dl->rx_level = dbm2rxlev(avg_dbm8 / (8*4));
+
+ num_biterr = dsp_api.ndb->a_cd[2];
+ if (num_biterr > 0xff)
+ rx_tch_a.dl->num_biterr = 0xff;
+ else
+ rx_tch_a.dl->num_biterr = num_biterr;
+
+ rx_tch_a.dl->fire_crc = ((dsp_api.ndb->a_cd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
+
+ /* Update rx level for pm report */
+ pu_update_rx_level(rx_tch_a.dl->rx_level);
+
+ /* Copy actual data, skipping the information block [0,1,2] */
+ dsp_memcpy_from_api(rx_tch_a.di->data, &dsp_api.ndb->a_cd[3], 23, 0);
+
+ /* Give message to up layer */
+ l1_queue_for_l2(rx_tch_a.msg);
+ rx_tch_a.msg = NULL; rx_tch_a.dl = NULL; rx_tch_a.di = NULL;
+
+ /* Reset header */
+ dsp_api.ndb->a_cd[0] = (1<<B_FIRE1);
+ dsp_api.ndb->a_cd[2] = 0xffff;
+ }
+
+skip:
+ /* mark READ page as being used */
+ dsp_api.r_page_used = 1;
+
+ return 0;
+}
+
+static int l1s_tch_a_cmd(__unused uint8_t p1, __unused uint8_t p2, uint16_t p3)
+{
+ uint8_t mf_task_id = p3 & 0xff;
+ uint8_t chan_nr;
+ uint16_t arfcn;
+ uint8_t tsc, tn;
+ uint8_t tch_f_hn, tch_sub, tch_mode;
+ uint32_t fn_report;
+ uint8_t burst_id;
+
+ /* Get/compute various parameters */
+ rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
+ chan_nr = mframe_task2chan_nr(mf_task_id, tn);
+ tch_get_params(&l1s.next_time, chan_nr, &fn_report, &tch_f_hn, &tch_sub, &tch_mode);
+ burst_id = (fn_report - 12) / 26;
+
+ /* Load SACCH data if we start a new burst */
+ if (burst_id == 0) {
+ uint16_t *info_ptr = dsp_api.ndb->a_cu;
+ struct msgb *msg;
+ const uint8_t *data;
+
+ /* If the TX queue is empty, send dummy measurement */
+ msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_SACCH]);
+ data = msg ? msg->l3h : pu_get_meas_frame();
+
+ /* Fill data block header */
+ info_ptr[0] = (1 << B_BLUD); /* 1st word: Set B_BLU bit. */
+ info_ptr[1] = 0; /* 2nd word: cleared. */
+ info_ptr[2] = 0; /* 3nd word: cleared. */
+
+ /* Copy the actual data after the header */
+ dsp_memcpy_to_api(&info_ptr[3], data, 23, 0);
+
+ /* Indicate completion (FIXME: early but easier this way for now) */
+ if (msg) {
+ last_tx_tch_fn = l1s.next_time.fn;
+ last_tx_tch_type |= TX_TYPE_SACCH;
+ l1s_compl_sched(L1_COMPL_TX_TCH);
+ }
+
+ /* Free msg now that we're done with it */
+ if (msg)
+ msgb_free(msg);
+ }
+
+ /* Allocate RX burst */
+ if (burst_id == 0) {
+ /* Clear 'dangling' msgb */
+ if (rx_tch_a.msg) {
+ /* Can happen if the task was shutdown in the middle of
+ * 4 bursts ... */
+ msgb_free(rx_tch_a.msg);
+ }
+
+ /* Allocate burst */
+ /* FIXME: we actually want all allocation out of L1S! */
+ rx_tch_a.msg = l1ctl_msgb_alloc(L1CTL_DATA_IND);
+ if (!rx_tch_a.msg)
+ printf("tch_a_cmd(0): unable to allocate msgb\n");
+
+ rx_tch_a.dl = (struct l1ctl_info_dl *) msgb_put(rx_tch_a.msg, sizeof(*rx_tch_a.dl));
+ rx_tch_a.di = (struct l1ctl_data_ind *) msgb_put(rx_tch_a.msg, sizeof(*rx_tch_a.di));
+
+ /* Pre-fill DL header with some info about burst(0) */
+ rx_tch_a.dl->chan_nr = chan_nr;
+ rx_tch_a.dl->link_id = 0x40; /* SACCH */
+ rx_tch_a.dl->band_arfcn = htons(arfcn);
+ rx_tch_a.dl->frame_nr = htonl(l1s.next_time.fn);
+ }
+
+ /* Configure DSP for TX/RX */
+ l1s_tx_apc_helper(arfcn);
+
+ dsp_load_tch_param(
+ &l1s.next_time,
+ tch_mode, tch_f_hn ? TCH_F : TCH_H, tch_sub,
+ 0, 0, tn
+ );
+
+ dsp_load_rx_task(TCHA_DSP_TASK, 0, tsc); /* burst_id unused for TCHA */
+ l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB, 0);
+
+ dsp_load_tx_task(TCHA_DSP_TASK, 0, tsc); /* burst_id unused for TCHA */
+ l1s_tx_win_ctrl(arfcn | ARFCN_UPLINK, L1_TXWIN_NB, 0, 3);
+
+ return 0;
+}
+
+
+const struct tdma_sched_item tch_a_sched_set[] = {
+ SCHED_ITEM_DT(l1s_tch_a_cmd, 0, 0, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_tch_a_resp, 0, 0, -4), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
diff --git a/src/target/firmware/layer1/prim_tx_nb.c b/src/target/firmware/layer1/prim_tx_nb.c
new file mode 100644
index 00000000..df13c757
--- /dev/null
+++ b/src/target/firmware/layer1/prim_tx_nb.c
@@ -0,0 +1,173 @@
+/* Layer 1 - Transmit Normal Burst */
+
+/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+
+#include <layer1/sync.h>
+#include <layer1/agc.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/mframe_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+#include <layer1/rfch.h>
+#include <layer1/prim.h>
+
+#include <l1ctl_proto.h>
+
+
+static uint32_t last_txnb_fn;
+
+/* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB) */
+static int l1s_tx_resp(__unused uint8_t p1, __unused uint8_t burst_id,
+ __unused uint16_t p3)
+{
+ putchart('t');
+
+ dsp_api.r_page_used = 1;
+
+ if (burst_id == 3) {
+ last_txnb_fn = l1s.current_time.fn - 4;
+ l1s_compl_sched(L1_COMPL_TX_NB);
+ }
+
+ return 0;
+}
+
+/* p1: type of operation (0: one NB, 1: one RACH burst, 2: four NB) */
+static int l1s_tx_cmd(uint8_t p1, uint8_t burst_id, uint16_t p3)
+{
+ uint16_t arfcn;
+ uint8_t tsc, tn;
+ uint8_t mf_task_id = p3 & 0xff;
+ uint8_t mf_task_flags = p3 >> 8;
+
+ putchart('T');
+
+ /* before sending first of the four bursts, copy data to API ram */
+ if (burst_id == 0) {
+ uint16_t *info_ptr = dsp_api.ndb->a_cu;
+ struct msgb *msg;
+ const uint8_t *data;
+
+ /* distinguish between DCCH and ACCH */
+ if (mf_task_flags & MF_F_SACCH) {
+ msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_SACCH]);
+ data = msg ? msg->l3h : pu_get_meas_frame();
+ } else {
+ msg = msgb_dequeue(&l1s.tx_queue[L1S_CHAN_MAIN]);
+ data = msg ? msg->l3h : pu_get_idle_frame();
+ }
+
+ /* Fill data block Header */
+ info_ptr[0] = (1 << B_BLUD); // 1st word: Set B_BLU bit.
+ info_ptr[1] = 0; // 2nd word: cleared.
+ info_ptr[2] = 0; // 3rd word: cleared.
+
+ /* Copy the actual data after the header */
+ dsp_memcpy_to_api(&info_ptr[3], data, 23, 0);
+
+ if (msg)
+ msgb_free(msg);
+ }
+
+ rfch_get_params(&l1s.next_time, &arfcn, &tsc, &tn);
+
+ l1s_tx_apc_helper(arfcn);
+
+ if (p1 == 0)
+ /* DUL_DSP_TASK, one normal burst */
+ dsp_load_tch_param(&l1s.next_time,
+ SIG_ONLY_MODE, INVALID_CHANNEL, 0, 0, 0, tn);
+
+ else if (p1 == 2)
+ /* DUL_DSP_TASK, four normal bursts */
+ dsp_load_tch_param(&l1s.next_time,
+ SIG_ONLY_MODE, SDCCH_4, 0, 0, 0, tn);
+
+ dsp_load_tx_task(DUL_DSP_TASK, burst_id, tsc);
+
+ l1s_tx_win_ctrl(arfcn | ARFCN_UPLINK, L1_TXWIN_NB, 0, 3);
+
+ return 0;
+}
+
+/* Asynchronous completion handler for NB transmit */
+static void l1a_tx_nb_compl(__unused enum l1_compl c)
+{
+ struct msgb *msg;
+
+ msg = l1_create_l2_msg(L1CTL_DATA_CONF, last_txnb_fn, 0, 0);
+ l1_queue_for_l2(msg);
+}
+
+void l1s_tx_test(uint8_t base_fn, uint8_t type)
+{
+ printf("Starting TX %d\n", type);
+
+ if (type == 0) {// one normal burst
+ tdma_schedule(base_fn, &l1s_tx_cmd, 0, 0, 0, 3);
+ tdma_schedule(base_fn + 2, &l1s_tx_resp, 0, 0, 0, 3);
+ } else if (type == 2) { // four normal bursts
+ tdma_schedule(base_fn, &l1s_tx_cmd, 2, 0, 0, 3);
+ tdma_schedule(base_fn + 1, &l1s_tx_cmd, 2, 1, 0, 3);
+ tdma_schedule(base_fn + 2, &l1s_tx_resp, 2, 0, 0, 3);
+ tdma_schedule(base_fn + 2, &l1s_tx_cmd, 2, 2, 0, 3);
+ tdma_schedule(base_fn + 3, &l1s_tx_resp, 2, 1, 0, 3);
+ tdma_schedule(base_fn + 3, &l1s_tx_cmd, 2, 3, 0, 3);
+ tdma_schedule(base_fn + 4, &l1s_tx_resp, 2, 2, 0, 3);
+ tdma_schedule(base_fn + 5, &l1s_tx_resp, 2, 3, 0, 3);
+ }
+}
+
+/* sched sets for uplink */
+const struct tdma_sched_item nb_sched_set_ul[] = {
+ SCHED_ITEM_DT(l1s_tx_cmd, 3, 2, 0), SCHED_END_FRAME(),
+ SCHED_ITEM_DT(l1s_tx_cmd, 3, 2, 1), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_tx_resp, -4, 2, 0), SCHED_ITEM_DT(l1s_tx_cmd, 3, 2, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_tx_resp, -4, 2, 1), SCHED_ITEM_DT(l1s_tx_cmd, 3, 2, 3), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_tx_resp, -4, 2, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_tx_resp, -4, 2, 3), SCHED_END_FRAME(),
+ SCHED_END_SET()
+};
+
+static __attribute__ ((constructor)) void prim_tx_nb_init(void)
+{
+ l1s.completion[L1_COMPL_TX_NB] = &l1a_tx_nb_compl;
+}
diff --git a/src/target/firmware/layer1/prim_utils.c b/src/target/firmware/layer1/prim_utils.c
new file mode 100644
index 00000000..c85da717
--- /dev/null
+++ b/src/target/firmware/layer1/prim_utils.c
@@ -0,0 +1,74 @@
+/* Layer 1 Various primitive utilities */
+
+/* (C) 2010 by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+
+#include <osmocom/core/msgb.h>
+#include <layer1/sync.h>
+
+
+static const uint8_t ubUui[23] = {
+ /* dummy lapdm header */
+ 0x01, 0x03, 0x01,
+
+ /* fill bytes */
+ 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+ 0x2b, 0x2b, 0x2b, 0x2b
+};
+
+static uint8_t ubMeas[23] = {
+ /* L1 SAACH pseudo-header */
+ 0x0f, 0x00,
+
+ /* lapdm header */
+ 0x01, 0x03, 0x49,
+
+ /* Measurement report */
+ 0x06, 0x15, 0x36, 0x36, 0x01, 0xC0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
+
+
+const uint8_t *pu_get_idle_frame(void)
+{
+ return ubUui;
+}
+
+void pu_update_rx_level(uint8_t rx_level)
+{
+ ubMeas[7] = ubMeas[8] = rx_level;
+}
+
+const uint8_t *pu_get_meas_frame(void)
+{
+ if (l1s.tx_meas) {
+ return l1s.tx_meas->l3h;
+ } else {
+ /* Update L1 SAACH pseudo-header */
+ ubMeas[0] = l1s.tx_power;
+ ubMeas[1] = l1s.ta;
+
+ return ubMeas;
+ }
+}
diff --git a/src/target/firmware/layer1/rfch.c b/src/target/firmware/layer1/rfch.c
new file mode 100644
index 00000000..d0818d04
--- /dev/null
+++ b/src/target/firmware/layer1/rfch.c
@@ -0,0 +1,152 @@
+/* RF Channel utilities */
+
+/* (C) 2010 by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <layer1/sync.h>
+
+
+/*
+ * Hopping sequence generation
+ *
+ * The algorithm is explained in GSM 05.02 Section 6.2.3
+ *
+ * if HSN = 0 (cyclic hopping) then:
+ * MAI, integer (0 .. N-1) :
+ * MAI = (FN + MAIO) modulo N
+ *
+ * else:
+ * M, integer (0 .. 152) :
+ * M = T2 + RNTABLE((HSN xor T1R) + T3)
+ *
+ * S, integer (0 .. N-1) :
+ * M' = M modulo (2 ^ NBIN)
+ * T' = T3 modulo (2 ^ NBIN)
+ *
+ * if M' < N then:
+ * S = M'
+ * else:
+ * S = (M'+T') modulo N
+ *
+ * MAI, integer (0 .. N-1) :
+ * MAI = (S + MAIO) modulo N
+ */
+
+static uint8_t rn_table[114] = {
+ 48, 98, 63, 1, 36, 95, 78, 102, 94, 73,
+ 0, 64, 25, 81, 76, 59, 124, 23, 104, 100,
+ 101, 47, 118, 85, 18, 56, 96, 86, 54, 2,
+ 80, 34, 127, 13, 6, 89, 57, 103, 12, 74,
+ 55, 111, 75, 38, 109, 71, 112, 29, 11, 88,
+ 87, 19, 3, 68, 110, 26, 33, 31, 8, 45,
+ 82, 58, 40, 107, 32, 5, 106, 92, 62, 67,
+ 77, 108, 122, 37, 60, 66, 121, 42, 51, 126,
+ 117, 114, 4, 90, 43, 52, 53, 113, 120, 72,
+ 16, 49, 7, 79, 119, 61, 22, 84, 9, 97,
+ 91, 15, 21, 24, 46, 39, 93, 105, 65, 70,
+ 125, 99, 17, 123,
+};
+
+
+static int pow_nbin_mask(int n)
+{
+ int x;
+ x = (n ) |
+ (n >> 1) |
+ (n >> 2) |
+ (n >> 3) |
+ (n >> 4) |
+ (n >> 5) |
+ (n >> 6);
+ return x;
+}
+
+static int16_t rfch_hop_seq_gen(struct gsm_time *t,
+ uint8_t hsn, uint8_t maio,
+ uint8_t n, uint16_t *arfcn_tbl)
+{
+ int mai;
+
+ if (!hsn) {
+ /* cyclic hopping */
+ mai = (t->fn + maio) % n;
+ } else {
+ /* pseudo random hopping */
+ int m, mp, tp, s, pnm;
+
+ pnm = pow_nbin_mask(n);
+
+ m = t->t2 + rn_table[(hsn ^ (t->t1 & 63)) + t->t3];
+ mp = m & pnm;
+
+ if (mp < n)
+ s = mp;
+ else {
+ tp = t->t3 & pnm;
+ s = (mp + tp) % n;
+ }
+
+ mai = (s + maio) % n;
+ }
+
+ return arfcn_tbl ? arfcn_tbl[mai] : mai;
+}
+
+
+/* RF Channel parameters */
+void rfch_get_params(struct gsm_time *t,
+ uint16_t *arfcn_p, uint8_t *tsc_p, uint8_t *tn_p)
+{
+ if (l1s.dedicated.type == GSM_DCHAN_NONE) {
+ /* Serving cell only */
+ if (arfcn_p)
+ *arfcn_p = l1s.serving_cell.arfcn;
+
+ if (tsc_p)
+ *tsc_p = l1s.serving_cell.bsic & 0x7;
+
+ if (tn_p)
+ *tn_p = 0;
+ } else {
+ /* Dedicated channel */
+ if (arfcn_p) {
+ if (l1s.dedicated.h) {
+ *arfcn_p = rfch_hop_seq_gen(t,
+ l1s.dedicated.h1.hsn,
+ l1s.dedicated.h1.maio,
+ l1s.dedicated.h1.n,
+ l1s.dedicated.h1.ma);
+ } else {
+ *arfcn_p = l1s.dedicated.h0.arfcn;
+ }
+ }
+
+ if (tsc_p)
+ *tsc_p = l1s.dedicated.tsc;
+
+ if (tn_p)
+ *tn_p = l1s.dedicated.tn;
+ }
+}
+
diff --git a/src/target/firmware/layer1/sched_gsmtime.c b/src/target/firmware/layer1/sched_gsmtime.c
new file mode 100644
index 00000000..01e22ca3
--- /dev/null
+++ b/src/target/firmware/layer1/sched_gsmtime.c
@@ -0,0 +1,119 @@
+/* GSM-Time One-shot Event Scheduler Implementation (on top of TDMA sched) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <debug.h>
+#include <osmocom/core/linuxlist.h>
+
+#include <layer1/tdma_sched.h>
+#include <layer1/sched_gsmtime.h>
+
+static struct sched_gsmtime_event sched_gsmtime_events[16];
+static LLIST_HEAD(active_evts);
+static LLIST_HEAD(inactive_evts);
+
+/* Scheduling of a tdma_sched_item list one-shot at a given GSM time */
+int sched_gsmtime(const struct tdma_sched_item *si, uint32_t fn, uint16_t p3)
+{
+ struct llist_head *lh;
+ struct sched_gsmtime_event *evt, *cur;
+
+ printd("sched_gsmtime(si=%p, fn=%u)\n", si, fn);
+
+ /* obtain a free/inactive event structure */
+ if (llist_empty(&inactive_evts))
+ return -EBUSY;
+ lh = inactive_evts.next;
+ llist_del(lh);
+ evt = llist_entry(lh, struct sched_gsmtime_event, list);
+
+ evt->fn = fn;
+ evt->si = si;
+ evt->p3 = p3;
+
+ /* do a sorted insert into the list, i.e. insert the new
+ * event _before_ the first entry that has a higher fn */
+ llist_for_each_entry(cur, &active_evts, list) {
+ if (cur->fn > evt->fn) {
+ llist_add_tail(lh, &cur->list);
+ return 0;
+ }
+ }
+
+ /* if we reach here, active_evts is empty _OR_ new event
+ * is after all the other events: append at end of list */
+ llist_add_tail(lh, &active_evts);
+
+ return 0;
+}
+
+/* how many TDMA frame ticks should we schedule events ahead? */
+#define SCHEDULE_AHEAD 2
+
+/* how long do we need to tell the DSP in advance what we want to do? */
+#define SCHEDULE_LATENCY 1
+
+/* execute all GSMTIME one-shot events pending for 'fn' */
+int sched_gsmtime_execute(uint32_t fn)
+{
+ struct sched_gsmtime_event *evt, *evt2;
+ int num = 0;
+
+ llist_for_each_entry_safe(evt, evt2, &active_evts, list) {
+ if (evt->fn == fn + SCHEDULE_AHEAD) {
+ printd("sched_gsmtime_execute(time=%u): fn=%u si=%p\n", fn, evt->fn, evt->si);
+ tdma_schedule_set(SCHEDULE_AHEAD-SCHEDULE_LATENCY,
+ evt->si, evt->p3);
+ llist_del(&evt->list);
+ /* put event back in list of inactive (free) events */
+ llist_add(&evt->list, &inactive_evts);
+ num++;
+ } if (evt->fn > fn + SCHEDULE_AHEAD) {
+ /* break the loop as our list is ordered */
+ break;
+ }
+ }
+ return num;
+}
+
+void sched_gsmtime_init(void)
+{
+ unsigned int i;
+
+ printd("sched_gsmtime_init()\n");
+
+ for (i = 0; i < ARRAY_SIZE(sched_gsmtime_events); i++)
+ llist_add(&sched_gsmtime_events[i].list, &inactive_evts);
+}
+
+void sched_gsmtime_reset(void)
+{
+ struct sched_gsmtime_event *evt, *evt2;
+
+ llist_for_each_entry_safe(evt, evt2, &active_evts, list) {
+ llist_del(&evt->list);
+ /* put event back in list of inactive (free) events */
+ llist_add(&evt->list, &inactive_evts);
+ }
+}
diff --git a/src/target/firmware/layer1/sync.c b/src/target/firmware/layer1/sync.c
new file mode 100644
index 00000000..36f42975
--- /dev/null
+++ b/src/target/firmware/layer1/sync.c
@@ -0,0 +1,402 @@
+/* Synchronous part of GSM Layer 1 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
+ * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <memory.h>
+#include <byteorder.h>
+#include <asm/system.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/msgb.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+
+#include <abb/twl3025.h>
+
+//#define DEBUG_EVERY_TDMA
+
+#include <layer1/sync.h>
+#include <layer1/afc.h>
+#include <layer1/agc.h>
+#include <layer1/apc.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/mframe_sched.h>
+#include <layer1/sched_gsmtime.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+
+#include <l1ctl_proto.h>
+
+struct l1s_state l1s;
+
+void l1s_time_inc(struct gsm_time *time, uint32_t delta_fn)
+{
+ ADD_MODULO(time->fn, delta_fn, GSM_MAX_FN);
+
+ if (delta_fn == 1) {
+ ADD_MODULO(time->t2, 1, 26);
+ ADD_MODULO(time->t3, 1, 51);
+
+ /* if the new frame number is a multiple of 51 */
+ if (time->t3 == 0) {
+ ADD_MODULO(time->tc, 1, 8);
+
+ /* if new FN is multiple of 51 and 26 */
+ if (time->t2 == 0)
+ ADD_MODULO(time->t1, 1, 2048);
+ }
+ } else
+ gsm_fn2gsmtime(time, time->fn);
+}
+
+void l1s_time_dump(const struct gsm_time *time)
+{
+ printf("fn=%lu(%u/%2u/%2u)", time->fn, time->t1, time->t2, time->t3);
+}
+
+/* clip a signed 16bit value at a certain limit */
+int16_t clip_int16(int16_t angle, int16_t clip_at)
+{
+ if (angle > clip_at)
+ angle = clip_at;
+ else if (angle < -clip_at)
+ angle = -clip_at;
+
+ return angle;
+}
+
+int16_t l1s_snr_int(uint16_t snr)
+{
+ return snr >> 10;
+}
+
+uint16_t l1s_snr_fract(uint16_t snr)
+{
+ uint32_t fract = snr & 0x3ff;
+ fract = fract * 1000 / (2 << 10);
+
+ return fract & 0xffff;
+}
+
+#define AFC_MAX_ANGLE 328 /* 0.01 radian in fx1.15 */
+
+/* synchronize the L1S to a new timebase (typically a new cell */
+void synchronize_tdma(struct l1_cell_info *cinfo)
+{
+ int32_t fn_offset;
+ uint32_t tpu_shift = cinfo->time_alignment;
+
+ /* NB detection only works if the TOA of the SB
+ * is within 0...8. We have to add 75 to get an SB TOA of 4. */
+ tpu_shift += 75;
+
+ tpu_shift = (l1s.tpu_offset + tpu_shift) % QBITS_PER_TDMA;
+
+ fn_offset = cinfo->fn_offset - 1;
+
+ /* if we're already very close to the end of the TPU frame, the
+ * next interrupt will basically occur now and we need to
+ * compensate */
+ if (tpu_shift < SWITCH_TIME)
+ fn_offset++;
+
+#if 0 /* probably wrong as we already added "offset" and "shift" above */
+ /* increment the TPU quarter-bit offset */
+ l1s.tpu_offset = (l1s.tpu_offset + tpu_shift) % TPU_RANGE;
+#else
+ l1s.tpu_offset = tpu_shift;
+#endif
+
+ puts("Synchronize_TDMA\n");
+ /* request the TPU to adjust the SYNCHRO and OFFSET registers */
+ tpu_enq_at(SWITCH_TIME);
+ tpu_enq_sync(l1s.tpu_offset);
+#if 0
+ /* FIXME: properly end the TPU window at the emd of l1_sync() */
+ tpu_end_scenario();
+#endif
+
+ /* Change the current time to reflect the new value */
+ l1s_time_inc(&l1s.current_time, fn_offset);
+ l1s.next_time = l1s.current_time;
+ l1s_time_inc(&l1s.next_time, 1);
+
+ /* The serving cell now no longer has a frame or bit offset */
+ cinfo->fn_offset = 0;
+ cinfo->time_alignment = 0;
+}
+
+void l1s_reset_hw(void)
+{
+ dsp_api.w_page = 0;
+ dsp_api.r_page = 0;
+ dsp_api.r_page_used = 0;
+ dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0;
+ dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0;
+ dsp_api.ndb->d_dsp_page = 0;
+
+ /* we have to really reset the TPU, otherwise FB detection
+ * somtimes returns wrong TOA values. */
+ tpu_reset(1);
+ tpu_reset(0);
+ tpu_rewind();
+ tpu_enq_wait(5); /* really needed ? */
+ tpu_enq_sync(l1s.tpu_offset);
+ tpu_end_scenario();
+}
+
+/* Lost TDMA interrupt detection. This works by starting a hardware timer
+ * that is clocked by the same master clock source (VCTCXO). We expect
+ * 1875 timer ticks in the duration of a TDMA frame (5000 qbits / 1250 bits) */
+
+/* Timer for detecting lost IRQ */
+#define TIMER_TICKS_PER_TDMA 1875
+#define TIMER_TICK_JITTER 1
+
+static int last_timestamp;
+
+static inline void check_lost_frame(void)
+{
+ int diff, timestamp = hwtimer_read(1);
+
+ if (last_timestamp < timestamp)
+ last_timestamp += (4*TIMER_TICKS_PER_TDMA);
+
+ diff = last_timestamp - timestamp;
+
+ /* allow for a bit of jitter */
+ if (diff < TIMER_TICKS_PER_TDMA - TIMER_TICK_JITTER ||
+ diff > TIMER_TICKS_PER_TDMA + TIMER_TICK_JITTER)
+ printf("LOST %d!\n", diff);
+
+ last_timestamp = timestamp;
+}
+
+/* schedule a completion */
+void l1s_compl_sched(enum l1_compl c)
+{
+ unsigned long flags;
+
+ local_firq_save(flags);
+ l1s.scheduled_compl |= (1 << c);
+ local_irq_restore(flags);
+}
+
+/* main routine for synchronous part of layer 1, called by frame interrupt
+ * generated by TPU once every TDMA frame */
+static void l1_sync(void)
+{
+ uint16_t sched_flags;
+
+ putchart('+');
+
+ check_lost_frame();
+
+ /* Increment Time */
+ l1s.current_time = l1s.next_time;
+ l1s_time_inc(&l1s.next_time, 1);
+ //l1s_time_dump(&l1s.current_time); putchar(' ');
+
+ dsp_api.frame_ctr++;
+ dsp_api.r_page_used = 0;
+
+ /* Update pointers */
+ if (dsp_api.w_page == 0)
+ dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0;
+ else
+ dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_1;
+
+ if (dsp_api.r_page == 0)
+ dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0;
+ else
+ dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_1;
+
+ /* Reset MCU->DSP page */
+ dsp_api_memset((uint16_t *) dsp_api.db_w, sizeof(*dsp_api.db_w));
+
+ /* Update AFC */
+ afc_load_dsp();
+
+ if (dsp_api.ndb->d_error_status) {
+ printf("DSP Error Status: %u\n", dsp_api.ndb->d_error_status);
+ dsp_api.ndb->d_error_status = 0;
+ }
+
+ /* execute the sched_items that have been scheduled for this
+ * TDMA frame (including setup/cleanup steps) */
+ sched_flags = tdma_sched_flag_scan();
+
+ if (sched_flags & TDMA_IFLG_TPU)
+ l1s_win_init();
+
+ tdma_sched_execute();
+
+ if (dsp_api.r_page_used) {
+ /* clear and switch the read page */
+ dsp_api_memset((uint16_t *) dsp_api.db_r,
+ sizeof(*dsp_api.db_r));
+
+ /* TSM30 does it (really needed ?):
+ * Set crc result as "SB not found". */
+ dsp_api.db_r->a_sch[0] = (1<<B_SCH_CRC); /* B_SCH_CRC =1, BLUD =0 */
+
+ dsp_api.r_page ^= 1;
+ }
+
+ if (sched_flags & TDMA_IFLG_DSP)
+ dsp_end_scenario();
+
+ if (sched_flags & TDMA_IFLG_TPU)
+ tpu_end_scenario();
+
+ /* schedule new / upcoming TDMA items */
+ mframe_schedule();
+ /* schedule new / upcoming one-shot events */
+ sched_gsmtime_execute(l1s.current_time.fn);
+
+ tdma_sched_advance();
+}
+
+/* ABORT command ********************************************************/
+
+static int l1s_abort_cmd(__unused uint8_t p1, __unused uint8_t p2,
+ __unused uint16_t p3)
+{
+ putchart('A');
+
+ /* similar to l1s_reset_hw() without touching the TPU */
+
+ dsp_api.w_page = 0;
+ dsp_api.r_page = 0;
+ dsp_api.r_page_used = 0;
+ dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0;
+ dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0;
+
+ /* Reset task commands. */
+ dsp_api.db_w->d_task_d = NO_DSP_TASK; /* Init. RX task to NO TASK */
+ dsp_api.db_w->d_task_u = NO_DSP_TASK; /* Init. TX task to NO TASK */
+ dsp_api.db_w->d_task_ra = NO_DSP_TASK; /* Init. RA task to NO TASK */
+ dsp_api.db_w->d_task_md = NO_DSP_TASK; /* Init. MONITORING task to NO TASK */
+ dsp_api.ndb->d_dsp_page = 0;
+
+ /* Set "b_abort" to TRUE, dsp will reset current and pending tasks */
+ dsp_api.db_w->d_ctrl_system |= (1 << B_TASK_ABORT);
+ return 0;
+}
+
+void l1s_dsp_abort(void)
+{
+ /* abort right now */
+ tdma_schedule(0, &l1s_abort_cmd, 0, 0, 0, 10);
+}
+
+void l1s_tx_apc_helper(uint16_t arfcn)
+{
+ int16_t auxapc;
+ enum gsm_band band;
+ int i;
+
+ /* Get DAC setting */
+ band = gsm_arfcn2band(arfcn);
+ auxapc = apc_tx_pwrlvl2auxapc(band, l1s.tx_power);
+
+ /* Load the ApcOffset into the DSP */
+ #define MY_OFFSET 4
+ dsp_api.ndb->d_apcoff = ABB_VAL(APCOFF, (1 << 6) | MY_OFFSET) | 1; /* 2x slope for the GTA-02 ramp */
+
+ /* Load the TX Power into the DSP */
+ /*
+ If the power is too low (below 0 dBm) the ramp is not OK,
+ especially for GSM-1800. However an MS does not send below
+ 0dBm anyway.
+ */
+ dsp_api.db_w->d_power_ctl = ABB_VAL(AUXAPC, auxapc);
+
+ /* Update the ramp according to the PCL */
+ for (i = 0; i < 16; i++)
+ dsp_api.ndb->a_ramp[i] = ABB_VAL(APCRAM, twl3025_default_ramp[i]);
+
+ /* The Ramp Table is sent to ABB only once after RF init routine called */
+ dsp_api.db_w->d_ctrl_abb |= (1 << B_RAMP) | (1 << B_BULRAMPDEL);
+}
+
+/* Interrupt handler */
+static void frame_irq(__unused enum irq_nr nr)
+{
+ l1_sync();
+}
+
+/* reset the layer1 as part of synchronizing to a new cell */
+void l1s_reset(void)
+{
+ /* Reset state */
+ l1s.fb.mode = 0;
+ l1s.tx_power = 7; /* initial power reset */
+
+ /* Leave dedicated mode */
+ l1s.dedicated.type = GSM_DCHAN_NONE;
+
+ /* reset scheduler and hardware */
+ sched_gsmtime_reset();
+ mframe_reset();
+ tdma_sched_reset();
+ l1s_dsp_abort();
+
+ /* Cipher off */
+ dsp_load_ciph_param(0, NULL);
+}
+
+void l1s_init(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(l1s.tx_queue); i++)
+ INIT_LLIST_HEAD(&l1s.tx_queue[i]);
+ l1s.tx_meas = NULL;
+
+ sched_gsmtime_init();
+
+ /* register FRAME interrupt as FIQ so it can interrupt normal IRQs */
+ irq_register_handler(IRQ_TPU_FRAME, &frame_irq);
+ irq_config(IRQ_TPU_FRAME, 1, 1, 0);
+ irq_enable(IRQ_TPU_FRAME);
+
+ /* configure timer 1 to be auto-reload and have a prescale of 12 (13MHz/12 == qbit clock) */
+ hwtimer_enable(1, 1);
+ hwtimer_load(1, (1875*4)-1);
+ hwtimer_config(1, 0, 1);
+ hwtimer_enable(1, 1);
+}
+
diff --git a/src/target/firmware/layer1/tdma_sched.c b/src/target/firmware/layer1/tdma_sched.c
new file mode 100644
index 00000000..88129922
--- /dev/null
+++ b/src/target/firmware/layer1/tdma_sched.c
@@ -0,0 +1,244 @@
+/* TDMA Scheduler Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <defines.h>
+#include <debug.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <layer1/tdma_sched.h>
+#include <layer1/sync.h>
+
+#include <calypso/dsp.h>
+
+/* dummy function to mark end of set */
+int tdma_end_set(__unused uint8_t p1, __unused uint8_t p2,
+ __unused uint16_t p3)
+{
+ return 0;
+}
+
+static uint8_t wrap_bucket(uint8_t offset)
+{
+ uint16_t bucket;
+
+ bucket = (l1s.tdma_sched.cur_bucket + offset)
+ % ARRAY_SIZE(l1s.tdma_sched.bucket);
+
+ return bucket;
+}
+
+/* Schedule an item at 'frame_offset' TDMA frames in the future */
+int tdma_schedule(uint8_t frame_offset, tdma_sched_cb *cb,
+ uint8_t p1, uint8_t p2, uint16_t p3, int16_t prio)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ uint8_t bucket_nr = wrap_bucket(frame_offset);
+ struct tdma_sched_bucket *bucket = &sched->bucket[bucket_nr];
+ struct tdma_sched_item *sched_item;
+
+ if (bucket->num_items >= ARRAY_SIZE(bucket->item)) {
+ puts("tdma_schedule bucket overflow\n");
+ return -1;
+ }
+
+ sched_item = &bucket->item[bucket->num_items++];
+
+ sched_item->cb = cb;
+ sched_item->p1 = p1;
+ sched_item->p2 = p2;
+ sched_item->p3 = p3;
+ sched_item->prio = prio;
+
+ return 0;
+}
+
+/* Schedule a set of items starting from 'frame_offset' TDMA frames in the future */
+int tdma_schedule_set(uint8_t frame_offset, const struct tdma_sched_item *item_set, uint16_t p3)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ uint8_t bucket_nr = wrap_bucket(frame_offset);
+ int i, j;
+
+ for (i = 0, j = 0; 1; i++) {
+ const struct tdma_sched_item *sched_item = &item_set[i];
+ struct tdma_sched_bucket *bucket = &sched->bucket[bucket_nr];
+
+ if (sched_item->cb == &tdma_end_set) {
+ /* end of scheduler set, return */
+ break;
+ }
+
+ if (sched_item->cb == NULL) {
+ /* advance to next bucket (== TDMA frame) */
+ bucket_nr = wrap_bucket(++frame_offset);
+ j++;
+ continue;
+ }
+ /* check for bucket overflow */
+ if (bucket->num_items >= ARRAY_SIZE(bucket->item)) {
+ puts("tdma_schedule bucket overflow\n");
+ return -1;
+ }
+ /* copy the item from the set into the current bucket item position */
+ memcpy(&bucket->item[bucket->num_items], sched_item, sizeof(*sched_item));
+ bucket->item[bucket->num_items].p3 = p3;
+ bucket->num_items++;
+ }
+
+ return j;
+}
+
+/* Advance TDMA scheduler to the next bucket */
+void tdma_sched_advance(void)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ uint8_t next_bucket;
+
+ /* advance to the next bucket */
+ next_bucket = wrap_bucket(1);
+ sched->cur_bucket = next_bucket;
+}
+
+/* Scan current frame scheduled items for flags */
+uint16_t tdma_sched_flag_scan(void)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ struct tdma_sched_bucket *bucket;
+ int i;
+ uint16_t flags = 0;
+
+ /* determine current bucket */
+ bucket = &sched->bucket[sched->cur_bucket];
+
+ /* iterate over items in this bucket and call callback function */
+ for (i=0; i<bucket->num_items; i++) {
+ struct tdma_sched_item *item = &bucket->item[i];
+ flags |= item->flags;
+ }
+
+ return flags;
+}
+
+/* Sort a bucket entries by priority */
+static void _tdma_sched_bucket_sort(struct tdma_sched_bucket *bucket, int *seq)
+{
+ int i, j, k;
+ struct tdma_sched_item *item_i, *item_j;
+
+ /* initial sequence */
+ /* we need all the items because some call back may schedule
+ * new call backs 'on the fly' */
+ for (i=0; i<TDMASCHED_NUM_CB; i++)
+ seq[i] = i;
+
+ /* iterate over items in this bucket and sort them */
+ for (i=0; i<bucket->num_items; i++)
+ {
+ item_i = &bucket->item[seq[i]];
+
+ for (j=i+1; j<bucket->num_items; j++)
+ {
+ item_j = &bucket->item[seq[j]];
+
+ if (item_i->prio > item_j->prio)
+ {
+ item_i = item_j;
+ k = seq[i];
+ seq[i] = seq[j];
+ seq[j] = k;
+ }
+ }
+ }
+}
+
+/* Execute pre-scheduled events for current frame */
+int tdma_sched_execute(void)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ struct tdma_sched_bucket *bucket;
+ int i, num_events = 0;
+ int seq[TDMASCHED_NUM_CB];
+
+ /* determine current bucket */
+ bucket = &sched->bucket[sched->cur_bucket];
+
+ /* get sequence in priority order */
+ _tdma_sched_bucket_sort(bucket, seq);
+
+ /* iterate over items in this bucket and call callback function */
+ for (i = 0; i < bucket->num_items; i++) {
+ struct tdma_sched_item *item = &bucket->item[seq[i]];
+ int rc;
+
+ num_events++;
+
+ rc = item->cb(item->p1, item->p2, item->p3);
+ if (rc < 0) {
+ printf("Error %d during processing of item %u of bucket %u\n",
+ rc, i, sched->cur_bucket);
+ return rc;
+ }
+ /* if the cb() we just called has scheduled more items for the
+ * current TDMA, bucket->num_items will have increased and we
+ * will simply continue to execute them as intended. Priorities
+ * won't work though ! */
+ }
+
+ /* clear/reset the bucket */
+ bucket->num_items = 0;
+
+ /* return number of items that we called */
+ return num_events;
+}
+
+void tdma_sched_reset(void)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ unsigned int bucket_nr;
+
+ for (bucket_nr = 0; bucket_nr < ARRAY_SIZE(sched->bucket); bucket_nr++) {
+ struct tdma_sched_bucket *bucket = &sched->bucket[bucket_nr];
+ /* current bucket will be reset by iteration code above! */
+ if (bucket_nr != sched->cur_bucket)
+ bucket->num_items = 0;
+ }
+
+ /* Don't reset cur_bucket, as it would upset the bucket iteration code
+ * in tdma_sched_execute() */
+}
+
+void tdma_sched_dump(void)
+{
+ unsigned int i;
+
+ printf("\n(%2u)", l1s.tdma_sched.cur_bucket);
+ for (i = 0; i < ARRAY_SIZE(l1s.tdma_sched.bucket); i++) {
+ int bucket_nr = wrap_bucket(i);
+ struct tdma_sched_bucket *bucket = &l1s.tdma_sched.bucket[bucket_nr];
+ printf("%u:", bucket->num_items);
+ }
+ putchar('\n');
+}
diff --git a/src/target/firmware/layer1/toa.c b/src/target/firmware/layer1/toa.c
new file mode 100644
index 00000000..7d80d952
--- /dev/null
+++ b/src/target/firmware/layer1/toa.c
@@ -0,0 +1,80 @@
+/* AFC (Automatic Frequency Correction) Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <layer1/toa.h>
+#include <layer1/avg.h>
+#include <layer1/sync.h>
+
+/* Over how many TDMA frames do we want to average? */
+#define TOA_PERIOD 250
+/* How many of our measurements have to be valid? */
+#define TOA_MIN_MUN_VALID 125
+
+// FIXME:
+#define TOA_SNR_THRESHOLD 2560 /* 2.5 dB in fx6.10 */
+
+struct toa_state {
+ struct running_avg ravg; /* running average */
+};
+
+
+static void toa_ravg_output(struct running_avg *ravg, int32_t avg);
+
+static struct toa_state toa_state = {
+ .ravg = {
+ .outfn = &toa_ravg_output,
+ .period = TOA_PERIOD,
+ .min_valid = TOA_MIN_MUN_VALID,
+ },
+};
+
+void toa_input(int32_t offset, uint32_t snr)
+{
+ int valid = 1;
+
+ if (snr < TOA_SNR_THRESHOLD || offset < 0 || offset >31)
+ valid = 0;
+ runavg_input(&toa_state.ravg, offset, valid);
+ runavg_check_output(&toa_state.ravg);
+}
+
+void toa_reset(void)
+{
+ toa_state.ravg.num_samples = toa_state.ravg.num_samples_valid = 0;
+ toa_state.ravg.acc_val = 0;
+}
+
+/* callback function for runavg */
+static void toa_ravg_output(struct running_avg *ravg, int32_t avg)
+{
+ if (avg != 16) {
+ printf("TOA AVG is not 16 qbits, correcting (got %ld)\n", avg);
+ l1s.tpu_offset_correction = avg - 16;
+ }
+}
diff --git a/src/target/firmware/layer1/tpu_window.c b/src/target/firmware/layer1/tpu_window.c
new file mode 100644
index 00000000..f4e76c16
--- /dev/null
+++ b/src/target/firmware/layer1/tpu_window.c
@@ -0,0 +1,175 @@
+/* TPU window control routines for Layer 1 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <debug.h>
+#include <defines.h>
+#include <stdio.h>
+
+#include <rffe.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+
+#include <layer1/sync.h>
+#include <layer1/tpu_window.h>
+#include <layer1/rfch.h>
+
+/* all units in GSM quarter-bits (923.1ns) */
+#define L1_TDMA_LENGTH_Q 5000
+#define L1_BURST_LENGTH_Q 625 /* L1_TDMA_LENGTH_Q/8 */
+
+#define L1_NB_MARGIN_Q (3 * 4)
+#define L1_SB_MARGIN_Q (23 * 4)
+#define L1_TAIL_DURATION_Q (3 * 4)
+
+/* Sample length as required by the Calypso DSP */
+#define L1_NB_DURATION_Q (L1_BURST_LENGTH_Q + 2 * L1_NB_MARGIN_Q - L1_TAIL_DURATION_Q)
+#define L1_SB_DURATION_Q (L1_BURST_LENGTH_Q + 2 * L1_SB_MARGIN_Q - L1_TAIL_DURATION_Q)
+#define L1_FB_DURATION_Q (11 * L1_TDMA_LENGTH_Q + 2057) /* more than 11 full slots */
+#define L1_FB26_DURATION_Q (L1_TDMA_LENGTH_Q + 798)
+#define L1_PW_DURATION_Q 289
+
+#define DSP_SETUP_TIME 66
+
+static const uint16_t rx_burst_duration[_NUM_L1_RXWIN] = {
+ [L1_RXWIN_PW] = L1_PW_DURATION_Q,
+ [L1_RXWIN_FB] = L1_FB_DURATION_Q,
+ [L1_RXWIN_SB] = L1_SB_DURATION_Q,
+ [L1_RXWIN_NB] = L1_NB_DURATION_Q,
+};
+
+#define L1_TX_NB_DURATION_Q 626
+#define L1_TX_AB_DURATION_Q 386
+
+static const uint16_t tx_burst_duration[_NUM_L1_TXWIN] = {
+ [L1_TXWIN_NB] = L1_TX_NB_DURATION_Q,
+ [L1_TXWIN_AB] = L1_TX_AB_DURATION_Q,
+};
+
+
+static int _win_setup(__unused uint8_t p1, __unused uint8_t p2, __unused uint16_t p3)
+{
+ uint8_t tn;
+
+ rfch_get_params(&l1s.next_time, NULL, NULL, &tn);
+
+ l1s.tpu_offset = (5000 + l1s.tpu_offset + l1s.tpu_offset_correction) % 5000;
+ l1s.tpu_offset_correction = 0;
+
+ tpu_enq_at(4740);
+ tpu_enq_sync((5000 + l1s.tpu_offset + (L1_BURST_LENGTH_Q * tn)) % 5000);
+
+ return 0;
+}
+
+static int _win_cleanup(__unused uint8_t p1, __unused uint8_t p2, __unused uint16_t p3)
+{
+ uint8_t tn;
+
+ rfch_get_params(&l1s.next_time, NULL, NULL, &tn);
+
+ /* restore offset */
+ tpu_enq_offset((5000 + l1s.tpu_offset + (L1_BURST_LENGTH_Q * tn)) % 5000);
+
+ return 0;
+}
+
+void l1s_win_init(void)
+{
+ tdma_schedule(0, _win_setup, 0, 0, 0, -2);
+ tdma_schedule(0, _win_cleanup, 0, 0, 0, 9);
+}
+
+void l1s_rx_win_ctrl(uint16_t arfcn, enum l1_rxwin_type wtype, uint8_t tn_ofs)
+{
+ int16_t start;
+ int32_t stop; /* prevent overflow of int16_t in L1_RXWIN_FB */
+
+ /* TN offset & TA adjust */
+ start = DSP_SETUP_TIME;
+ start += L1_BURST_LENGTH_Q * tn_ofs;
+
+ stop = start + rx_burst_duration[wtype] - 1;
+
+ /* window open for TRF6151 */
+ /* FIXME: why do we need the magic value 100 ? */
+ rffe_mode(gsm_arfcn2band(arfcn), 0);
+ trf6151_rx_window(start - 100, arfcn);
+
+ /* Window open for ABB */
+ twl3025_downlink(1, start);
+
+ /* Delay 11 full TDMA frames */
+ if (wtype == L1_RXWIN_FB) {
+ uint8_t i;
+ for (i = 0; i < 11; i++)
+ tpu_enq_at(0);
+
+ stop -= 11 * L1_TDMA_LENGTH_Q;
+ }
+
+ /* Window close for ABB */
+ twl3025_downlink(0, stop & 0xffff);
+
+ /* window close for TRF6151 */
+ trf6151_set_mode(TRF6151_IDLE);
+}
+
+void l1s_tx_win_ctrl(uint16_t arfcn, enum l1_txwin_type wtype, uint8_t pwr, uint8_t tn_ofs)
+{
+ uint16_t offset;
+
+ /* TN offset & TA adjust */
+ offset = 28; /* ("+ 32" gives a TA of 1) */
+ offset += L1_BURST_LENGTH_Q * tn_ofs;
+ offset -= l1s.ta << 2;
+
+#ifdef CONFIG_TX_ENABLE
+ /* window open for TRF6151 */
+ trf6151_tx_window(offset, arfcn);
+#endif
+
+ /* Window open for ABB */
+ twl3025_uplink(1, offset);
+
+#ifdef CONFIG_TX_ENABLE
+ /* Window open for RFFE */
+ rffe_mode(gsm_arfcn2band(arfcn), 1);
+#endif
+
+ /* Window close for ABB */
+ twl3025_uplink(0, tx_burst_duration[wtype] + offset + 2); // TODO: "+ 2"
+
+ /* window close for TRF6151 */
+ trf6151_set_mode(TRF6151_IDLE);
+
+ /* Window close for RFFE */
+ rffe_mode(gsm_arfcn2band(arfcn), 0);
+}
+
+void tpu_end_scenario(void)
+{
+ tpu_enq_sleep();
+ tpu_enable(1);
+}
diff --git a/src/target/firmware/lib/Makefile b/src/target/firmware/lib/Makefile
new file mode 100644
index 00000000..83f9966b
--- /dev/null
+++ b/src/target/firmware/lib/Makefile
@@ -0,0 +1,7 @@
+
+LIBRARIES+=mini
+mini_DIR=lib
+mini_SRCS=vsprintf.c string.c ctype.c printf.c console.c ctors.c \
+ changebit.S clearbit.S delay.c div64.S lib1funcs.S memcpy.S memset.S setbit.S testchangebit.S testclearbit.S testsetbit.S
+
+
diff --git a/src/target/firmware/lib/bitops.h b/src/target/firmware/lib/bitops.h
new file mode 100644
index 00000000..428c9a63
--- /dev/null
+++ b/src/target/firmware/lib/bitops.h
@@ -0,0 +1,33 @@
+ .macro bitop, instr
+ and r2, r0, #7
+ mov r3, #1
+ mov r3, r3, lsl r2
+ save_and_disable_irqs ip
+ ldrb r2, [r1, r0, lsr #3]
+ \instr r2, r2, r3
+ strb r2, [r1, r0, lsr #3]
+ restore_irqs ip
+ mov pc, lr
+ .endm
+
+/**
+ * testop - implement a test_and_xxx_bit operation.
+ * @instr: operational instruction
+ * @store: store instruction
+ *
+ * Note: we can trivially conditionalise the store instruction
+ * to avoid dirting the data cache.
+ */
+ .macro testop, instr, store
+ add r1, r1, r0, lsr #3
+ and r3, r0, #7
+ mov r0, #1
+ save_and_disable_irqs ip
+ ldrb r2, [r1]
+ tst r2, r0, lsl r3
+ \instr r2, r2, r0, lsl r3
+ \store r2, [r1]
+ restore_irqs ip
+ moveq r0, #0
+ mov pc, lr
+ .endm
diff --git a/src/target/firmware/lib/changebit.S b/src/target/firmware/lib/changebit.S
new file mode 100644
index 00000000..7c709fb3
--- /dev/null
+++ b/src/target/firmware/lib/changebit.S
@@ -0,0 +1,21 @@
+/*
+ * linux/arch/arm/lib/changebit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+/* Purpose : Function to change a bit
+ * Prototype: int change_bit(int bit, void *addr)
+ */
+ENTRY(_change_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_change_bit_le)
+ bitop eor
diff --git a/src/target/firmware/lib/clearbit.S b/src/target/firmware/lib/clearbit.S
new file mode 100644
index 00000000..cb48f7ac
--- /dev/null
+++ b/src/target/firmware/lib/clearbit.S
@@ -0,0 +1,22 @@
+/*
+ * linux/arch/arm/lib/clearbit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+/*
+ * Purpose : Function to clear a bit
+ * Prototype: int clear_bit(int bit, void *addr)
+ */
+ENTRY(_clear_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_clear_bit_le)
+ bitop bic
diff --git a/src/target/firmware/lib/console.c b/src/target/firmware/lib/console.c
new file mode 100644
index 00000000..7135ae25
--- /dev/null
+++ b/src/target/firmware/lib/console.c
@@ -0,0 +1,190 @@
+/* Ringbuffer based serial console layer, imported from OpenPCD */
+
+/* (C) 2006-2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <console.h>
+#include <uart.h>
+
+#include <asm/system.h>
+
+struct cons {
+ char buf[CONS_RB_SIZE];
+ char *next_inbyte;
+ char *next_outbyte;
+ int initialized;
+};
+static struct cons cons;
+
+void cons_init(void)
+{
+ memset(cons.buf, 0, sizeof(cons.buf));
+ cons.next_inbyte = &cons.buf[0];
+ cons.next_outbyte = &cons.buf[0];
+ cons.initialized = 1;
+}
+
+/* determine how many bytes are left in the ringbuffer without overwriting
+ bytes that haven't been written to the console yet */
+static int __cons_rb_space(void)
+{
+ if (cons.next_inbyte == cons.next_outbyte)
+ return sizeof(cons.buf)-1;
+ else if (cons.next_outbyte > cons.next_inbyte)
+ return (cons.next_outbyte - cons.next_inbyte) -1;
+ else
+ return sizeof(cons.buf) - 1 - (cons.next_inbyte - cons.next_outbyte);
+}
+
+/* pull one char out of debug ring buffer */
+static int cons_rb_pull(char *ret)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (cons.next_outbyte == cons.next_inbyte) {
+ local_irq_restore(flags);
+ return -1;
+ }
+
+ *ret = *cons.next_outbyte;
+
+ cons.next_outbyte++;
+ if (cons.next_outbyte >= &cons.buf[0]+sizeof(cons.buf)) {
+ cons.next_outbyte = &cons.buf[0];
+ }
+#if 0
+ else if (cons.next_outbyte > &cons.buf[0]+sizeof(cons.buf)) {
+ cons.next_outbyte -= sizeof(cons.buf);
+ }
+#endif
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+/* returns if everything was flushed (1) or if there's more to flush (0) */
+static void __rb_flush_wait(void)
+{
+ char ch;
+ while (cons_rb_pull(&ch) >= 0)
+ uart_putchar_wait(CONS_UART_NR, ch);
+}
+
+/* returns if everything was flushed (1) or if there's more to flush (0) */
+static int __rb_flush(void)
+{
+ while (!uart_tx_busy(CONS_UART_NR)) {
+ char ch;
+ if (cons_rb_pull(&ch) < 0) {
+ /* no more data to write, disable interest in Tx FIFO interrupts */
+ return 1;
+ }
+ uart_putchar_nb(CONS_UART_NR, ch);
+ }
+
+ /* if we reach here, UART Tx FIFO is busy again */
+ return 0;
+}
+
+/* flush pending data from debug ring buffer to serial port */
+int cons_rb_flush(void)
+{
+ return __rb_flush();
+}
+
+/* Append bytes to ring buffer, not more than we have left! */
+static void __cons_rb_append(const char *data, int len)
+{
+ if (cons.next_inbyte + len >= &cons.buf[0]+sizeof(cons.buf)) {
+ int before_tail = (&cons.buf[0]+sizeof(cons.buf)) - cons.next_inbyte;
+ /* copy the first part before we wrap */
+ memcpy(cons.next_inbyte, data, before_tail);
+ data += before_tail;
+ len -= before_tail;
+ /* reset the buffer */
+ cons.next_inbyte = &cons.buf[0];
+ }
+ memcpy(cons.next_inbyte, data, len);
+ cons.next_inbyte += len;
+}
+
+/* append bytes to the ringbuffer, do one wrap */
+int cons_rb_append(const char *data, int len)
+{
+ unsigned long flags;
+ int bytes_left;
+ const char *data_cur;
+
+ /* we will never be able to write more than the console buffer */
+ if (len > (int) sizeof(cons.buf))
+ len = sizeof(cons.buf);
+
+ local_irq_save(flags);
+
+ bytes_left = __cons_rb_space();
+ data_cur = data;
+
+ if (len > bytes_left) {
+ /* append what we can */
+ __cons_rb_append(data_cur, bytes_left);
+ /* busy-wait for all characters to be transmitted */
+ __rb_flush_wait();
+ /* fill it with the remaining bytes */
+ len -= bytes_left;
+ data_cur += bytes_left;
+ }
+ __cons_rb_append(data_cur, len);
+
+ /* we want to get Tx FIFO interrupts */
+ uart_irq_enable(CONS_UART_NR, UART_IRQ_TX_EMPTY, 1);
+
+ local_irq_restore(flags);
+
+ return len;
+}
+
+int cons_puts(const char *s)
+{
+ if (cons.initialized) {
+ return cons_rb_append(s, strlen(s));
+ } else {
+ /* if the console is not active yet, we need to fall back */
+ int i = strlen(s);
+ while (i--)
+ uart_putchar_wait(CONS_UART_NR, *s++);
+ return i;
+ }
+}
+
+int cons_putchar(char c)
+{
+ if (cons.initialized)
+ return cons_rb_append(&c, 1);
+ else {
+ /* if the console is not active yet, we need to fall back */
+ uart_putchar_wait(CONS_UART_NR, c);
+ return 0;
+ }
+}
diff --git a/src/target/firmware/lib/copy_template.S b/src/target/firmware/lib/copy_template.S
new file mode 100644
index 00000000..cab355c0
--- /dev/null
+++ b/src/target/firmware/lib/copy_template.S
@@ -0,0 +1,255 @@
+/*
+ * linux/arch/arm/lib/copy_template.s
+ *
+ * Code template for optimized memory copy functions
+ *
+ * Author: Nicolas Pitre
+ * Created: Sep 28, 2005
+ * Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This can be used to enable code to cacheline align the source pointer.
+ * Experiments on tested architectures (StrongARM and XScale) didn't show
+ * this a worthwhile thing to do. That might be different in the future.
+ */
+//#define CALGN(code...) code
+#define CALGN(code...)
+
+/*
+ * Theory of operation
+ * -------------------
+ *
+ * This file provides the core code for a forward memory copy used in
+ * the implementation of memcopy(), copy_to_user() and copy_from_user().
+ *
+ * The including file must define the following accessor macros
+ * according to the need of the given function:
+ *
+ * ldr1w ptr reg abort
+ *
+ * This loads one word from 'ptr', stores it in 'reg' and increments
+ * 'ptr' to the next word. The 'abort' argument is used for fixup tables.
+ *
+ * ldr4w ptr reg1 reg2 reg3 reg4 abort
+ * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ *
+ * This loads four or eight words starting from 'ptr', stores them
+ * in provided registers and increments 'ptr' past those words.
+ * The'abort' argument is used for fixup tables.
+ *
+ * ldr1b ptr reg cond abort
+ *
+ * Similar to ldr1w, but it loads a byte and increments 'ptr' one byte.
+ * It also must apply the condition code if provided, otherwise the
+ * "al" condition is assumed by default.
+ *
+ * str1w ptr reg abort
+ * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ * str1b ptr reg cond abort
+ *
+ * Same as their ldr* counterparts, but data is stored to 'ptr' location
+ * rather than being loaded.
+ *
+ * enter reg1 reg2
+ *
+ * Preserve the provided registers on the stack plus any additional
+ * data as needed by the implementation including this code. Called
+ * upon code entry.
+ *
+ * exit reg1 reg2
+ *
+ * Restore registers with the values previously saved with the
+ * 'preserv' macro. Called upon code termination.
+ */
+
+
+ enter r4, lr
+
+ subs r2, r2, #4
+ blt 8f
+ ands ip, r0, #3
+ PLD( pld [r1, #0] )
+ bne 9f
+ ands ip, r1, #3
+ bne 10f
+
+1: subs r2, r2, #(28)
+ stmfd sp!, {r5 - r8}
+ blt 5f
+
+ CALGN( ands ip, r1, #31 )
+ CALGN( rsb r3, ip, #32 )
+ CALGN( sbcnes r4, r3, r2 ) @ C is always set here
+ CALGN( bcs 2f )
+ CALGN( adr r4, 6f )
+ CALGN( subs r2, r2, r3 ) @ C gets set
+ CALGN( add pc, r4, ip )
+
+ PLD( pld [r1, #0] )
+2: PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #28] )
+ PLD( blt 4f )
+ PLD( pld [r1, #60] )
+ PLD( pld [r1, #92] )
+
+3: PLD( pld [r1, #124] )
+4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
+ subs r2, r2, #32
+ str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
+ bge 3b
+ PLD( cmn r2, #96 )
+ PLD( bge 4b )
+
+5: ands ip, r2, #28
+ rsb ip, ip, #32
+ addne pc, pc, ip @ C is always clear here
+ b 7f
+6: nop
+ ldr1w r1, r3, abort=20f
+ ldr1w r1, r4, abort=20f
+ ldr1w r1, r5, abort=20f
+ ldr1w r1, r6, abort=20f
+ ldr1w r1, r7, abort=20f
+ ldr1w r1, r8, abort=20f
+ ldr1w r1, lr, abort=20f
+
+ add pc, pc, ip
+ nop
+ nop
+ str1w r0, r3, abort=20f
+ str1w r0, r4, abort=20f
+ str1w r0, r5, abort=20f
+ str1w r0, r6, abort=20f
+ str1w r0, r7, abort=20f
+ str1w r0, r8, abort=20f
+ str1w r0, lr, abort=20f
+
+ CALGN( bcs 2b )
+
+7: ldmfd sp!, {r5 - r8}
+
+8: movs r2, r2, lsl #31
+ ldr1b r1, r3, ne, abort=21f
+ ldr1b r1, r4, cs, abort=21f
+ ldr1b r1, ip, cs, abort=21f
+ str1b r0, r3, ne, abort=21f
+ str1b r0, r4, cs, abort=21f
+ str1b r0, ip, cs, abort=21f
+
+ exit r4, pc
+
+9: rsb ip, ip, #4
+ cmp ip, #2
+ ldr1b r1, r3, gt, abort=21f
+ ldr1b r1, r4, ge, abort=21f
+ ldr1b r1, lr, abort=21f
+ str1b r0, r3, gt, abort=21f
+ str1b r0, r4, ge, abort=21f
+ subs r2, r2, ip
+ str1b r0, lr, abort=21f
+ blt 8b
+ ands ip, r1, #3
+ beq 1b
+
+10: bic r1, r1, #3
+ cmp ip, #2
+ ldr1w r1, lr, abort=21f
+ beq 17f
+ bgt 18f
+
+
+ .macro forward_copy_shift pull push
+
+ subs r2, r2, #28
+ blt 14f
+
+ CALGN( ands ip, r1, #31 )
+ CALGN( rsb ip, ip, #32 )
+ CALGN( sbcnes r4, ip, r2 ) @ C is always set here
+ CALGN( subcc r2, r2, ip )
+ CALGN( bcc 15f )
+
+11: stmfd sp!, {r5 - r9}
+
+ PLD( pld [r1, #0] )
+ PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #28] )
+ PLD( blt 13f )
+ PLD( pld [r1, #60] )
+ PLD( pld [r1, #92] )
+
+12: PLD( pld [r1, #124] )
+13: ldr4w r1, r4, r5, r6, r7, abort=19f
+ mov r3, lr, pull #\pull
+ subs r2, r2, #32
+ ldr4w r1, r8, r9, ip, lr, abort=19f
+ orr r3, r3, r4, push #\push
+ mov r4, r4, pull #\pull
+ orr r4, r4, r5, push #\push
+ mov r5, r5, pull #\pull
+ orr r5, r5, r6, push #\push
+ mov r6, r6, pull #\pull
+ orr r6, r6, r7, push #\push
+ mov r7, r7, pull #\pull
+ orr r7, r7, r8, push #\push
+ mov r8, r8, pull #\pull
+ orr r8, r8, r9, push #\push
+ mov r9, r9, pull #\pull
+ orr r9, r9, ip, push #\push
+ mov ip, ip, pull #\pull
+ orr ip, ip, lr, push #\push
+ str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
+ bge 12b
+ PLD( cmn r2, #96 )
+ PLD( bge 13b )
+
+ ldmfd sp!, {r5 - r9}
+
+14: ands ip, r2, #28
+ beq 16f
+
+15: mov r3, lr, pull #\pull
+ ldr1w r1, lr, abort=21f
+ subs ip, ip, #4
+ orr r3, r3, lr, push #\push
+ str1w r0, r3, abort=21f
+ bgt 15b
+ CALGN( cmp r2, #0 )
+ CALGN( bge 11b )
+
+16: sub r1, r1, #(\push / 8)
+ b 8b
+
+ .endm
+
+
+ forward_copy_shift pull=8 push=24
+
+17: forward_copy_shift pull=16 push=16
+
+18: forward_copy_shift pull=24 push=8
+
+
+/*
+ * Abort preamble and completion macros.
+ * If a fixup handler is required then those macros must surround it.
+ * It is assumed that the fixup code will handle the private part of
+ * the exit macro.
+ */
+
+ .macro copy_abort_preamble
+19: ldmfd sp!, {r5 - r9}
+ b 21f
+20: ldmfd sp!, {r5 - r8}
+21:
+ .endm
+
+ .macro copy_abort_end
+ ldmfd sp!, {r4, pc}
+ .endm
+
diff --git a/src/target/firmware/lib/ctors.c b/src/target/firmware/lib/ctors.c
new file mode 100644
index 00000000..982169df
--- /dev/null
+++ b/src/target/firmware/lib/ctors.c
@@ -0,0 +1,15 @@
+
+/* iterate over list of constructor functions and call each element */
+void do_global_ctors(const char *_ctors_start, const char *ctors_end)
+{
+ typedef void (*func_ptr)(void);
+ func_ptr *func, *ctors_start = (func_ptr *) _ctors_start;
+
+ /* skip the first entry, as it contains the number of
+ * constructors which we don't use */
+ ctors_start++;
+
+ for (func = ctors_start;
+ *func && (func != (func_ptr *) ctors_end); func++)
+ (*func)();
+}
diff --git a/src/target/firmware/lib/ctype.c b/src/target/firmware/lib/ctype.c
new file mode 100644
index 00000000..f3732140
--- /dev/null
+++ b/src/target/firmware/lib/ctype.c
@@ -0,0 +1,34 @@
+/*
+ * linux/lib/ctype.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <ctype.h>
+
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
+
diff --git a/src/target/firmware/lib/delay.c b/src/target/firmware/lib/delay.c
new file mode 100644
index 00000000..443ca827
--- /dev/null
+++ b/src/target/firmware/lib/delay.c
@@ -0,0 +1,16 @@
+#include <delay.h>
+
+/* FIXME: We need properly calibrated delay loops at some point! */
+void delay_us(unsigned int us)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < us*4; i++) { i; }
+}
+
+void delay_ms(unsigned int ms)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < ms*1300; i++) { i; }
+}
diff --git a/src/target/firmware/lib/div64.S b/src/target/firmware/lib/div64.S
new file mode 100644
index 00000000..7eeef50c
--- /dev/null
+++ b/src/target/firmware/lib/div64.S
@@ -0,0 +1,200 @@
+/*
+ * linux/arch/arm/lib/div64.S
+ *
+ * Optimized computation of 64-bit dividend / 32-bit divisor
+ *
+ * Author: Nicolas Pitre
+ * Created: Oct 5, 2003
+ * Copyright: Monta Vista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/linkage.h>
+
+#ifdef __ARMEB__
+#define xh r0
+#define xl r1
+#define yh r2
+#define yl r3
+#else
+#define xl r0
+#define xh r1
+#define yl r2
+#define yh r3
+#endif
+
+/*
+ * __do_div64: perform a division with 64-bit dividend and 32-bit divisor.
+ *
+ * Note: Calling convention is totally non standard for optimal code.
+ * This is meant to be used by do_div() from include/asm/div64.h only.
+ *
+ * Input parameters:
+ * xh-xl = dividend (clobbered)
+ * r4 = divisor (preserved)
+ *
+ * Output values:
+ * yh-yl = result
+ * xh = remainder
+ *
+ * Clobbered regs: xl, ip
+ */
+
+ENTRY(__do_div64)
+
+ @ Test for easy paths first.
+ subs ip, r4, #1
+ bls 9f @ divisor is 0 or 1
+ tst ip, r4
+ beq 8f @ divisor is power of 2
+
+ @ See if we need to handle upper 32-bit result.
+ cmp xh, r4
+ mov yh, #0
+ blo 3f
+
+ @ Align divisor with upper part of dividend.
+ @ The aligned divisor is stored in yl preserving the original.
+ @ The bit position is stored in ip.
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz yl, r4
+ clz ip, xh
+ sub yl, yl, ip
+ mov ip, #1
+ mov ip, ip, lsl yl
+ mov yl, r4, lsl yl
+
+#else
+
+ mov yl, r4
+ mov ip, #1
+1: cmp yl, #0x80000000
+ cmpcc yl, xh
+ movcc yl, yl, lsl #1
+ movcc ip, ip, lsl #1
+ bcc 1b
+
+#endif
+
+ @ The division loop for needed upper bit positions.
+ @ Break out early if dividend reaches 0.
+2: cmp xh, yl
+ orrcs yh, yh, ip
+ subcss xh, xh, yl
+ movnes ip, ip, lsr #1
+ mov yl, yl, lsr #1
+ bne 2b
+
+ @ See if we need to handle lower 32-bit result.
+3: cmp xh, #0
+ mov yl, #0
+ cmpeq xl, r4
+ movlo xh, xl
+ movlo pc, lr
+
+ @ The division loop for lower bit positions.
+ @ Here we shift remainer bits leftwards rather than moving the
+ @ divisor for comparisons, considering the carry-out bit as well.
+ mov ip, #0x80000000
+4: movs xl, xl, lsl #1
+ adcs xh, xh, xh
+ beq 6f
+ cmpcc xh, r4
+5: orrcs yl, yl, ip
+ subcs xh, xh, r4
+ movs ip, ip, lsr #1
+ bne 4b
+ mov pc, lr
+
+ @ The top part of remainder became zero. If carry is set
+ @ (the 33th bit) this is a false positive so resume the loop.
+ @ Otherwise, if lower part is also null then we are done.
+6: bcs 5b
+ cmp xl, #0
+ moveq pc, lr
+
+ @ We still have remainer bits in the low part. Bring them up.
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz xh, xl @ we know xh is zero here so...
+ add xh, xh, #1
+ mov xl, xl, lsl xh
+ mov ip, ip, lsr xh
+
+#else
+
+7: movs xl, xl, lsl #1
+ mov ip, ip, lsr #1
+ bcc 7b
+
+#endif
+
+ @ Current remainder is now 1. It is worthless to compare with
+ @ divisor at this point since divisor can not be smaller than 3 here.
+ @ If possible, branch for another shift in the division loop.
+ @ If no bit position left then we are done.
+ movs ip, ip, lsr #1
+ mov xh, #1
+ bne 4b
+ mov pc, lr
+
+8: @ Division by a power of 2: determine what that divisor order is
+ @ then simply shift values around
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz ip, r4
+ rsb ip, ip, #31
+
+#else
+
+ mov yl, r4
+ cmp r4, #(1 << 16)
+ mov ip, #0
+ movhs yl, yl, lsr #16
+ movhs ip, #16
+
+ cmp yl, #(1 << 8)
+ movhs yl, yl, lsr #8
+ addhs ip, ip, #8
+
+ cmp yl, #(1 << 4)
+ movhs yl, yl, lsr #4
+ addhs ip, ip, #4
+
+ cmp yl, #(1 << 2)
+ addhi ip, ip, #3
+ addls ip, ip, yl, lsr #1
+
+#endif
+
+ mov yh, xh, lsr ip
+ mov yl, xl, lsr ip
+ rsb ip, ip, #32
+ orr yl, yl, xh, lsl ip
+ mov xh, xl, lsl ip
+ mov xh, xh, lsr ip
+ mov pc, lr
+
+ @ eq -> division by 1: obvious enough...
+9: moveq yl, xl
+ moveq yh, xh
+ moveq xh, #0
+ moveq pc, lr
+
+ @ Division by 0:
+ str lr, [sp, #-8]!
+ bl __div0
+
+ @ as wrong as it could be...
+ mov yl, #0
+ mov yh, #0
+ mov xh, #0
+ ldr pc, [sp], #8
+
diff --git a/src/target/firmware/lib/lib1funcs.S b/src/target/firmware/lib/lib1funcs.S
new file mode 100644
index 00000000..b02a85eb
--- /dev/null
+++ b/src/target/firmware/lib/lib1funcs.S
@@ -0,0 +1,334 @@
+/*
+ * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines
+ *
+ * Author: Nicolas Pitre <nico@cam.org>
+ * - contributed to gcc-3.4 on Sep 30, 2003
+ * - adapted for the Linux kernel on Oct 2, 2003
+ */
+
+/* Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+
+
+.macro ARM_DIV_BODY dividend, divisor, result, curbit
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz \curbit, \divisor
+ clz \result, \dividend
+ sub \result, \curbit, \result
+ mov \curbit, #1
+ mov \divisor, \divisor, lsl \result
+ mov \curbit, \curbit, lsl \result
+ mov \result, #0
+
+#else
+
+ @ Initially shift the divisor left 3 bits if possible,
+ @ set curbit accordingly. This allows for curbit to be located
+ @ at the left end of each 4 bit nibbles in the division loop
+ @ to save one loop in most cases.
+ tst \divisor, #0xe0000000
+ moveq \divisor, \divisor, lsl #3
+ moveq \curbit, #8
+ movne \curbit, #1
+
+ @ Unless the divisor is very big, shift it up in multiples of
+ @ four bits, since this is the amount of unwinding in the main
+ @ division loop. Continue shifting until the divisor is
+ @ larger than the dividend.
+1: cmp \divisor, #0x10000000
+ cmplo \divisor, \dividend
+ movlo \divisor, \divisor, lsl #4
+ movlo \curbit, \curbit, lsl #4
+ blo 1b
+
+ @ For very big divisors, we must shift it a bit at a time, or
+ @ we will be in danger of overflowing.
+1: cmp \divisor, #0x80000000
+ cmplo \divisor, \dividend
+ movlo \divisor, \divisor, lsl #1
+ movlo \curbit, \curbit, lsl #1
+ blo 1b
+
+ mov \result, #0
+
+#endif
+
+ @ Division loop
+1: cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+ orrhs \result, \result, \curbit
+ cmp \dividend, \divisor, lsr #1
+ subhs \dividend, \dividend, \divisor, lsr #1
+ orrhs \result, \result, \curbit, lsr #1
+ cmp \dividend, \divisor, lsr #2
+ subhs \dividend, \dividend, \divisor, lsr #2
+ orrhs \result, \result, \curbit, lsr #2
+ cmp \dividend, \divisor, lsr #3
+ subhs \dividend, \dividend, \divisor, lsr #3
+ orrhs \result, \result, \curbit, lsr #3
+ cmp \dividend, #0 @ Early termination?
+ movnes \curbit, \curbit, lsr #4 @ No, any more bits to do?
+ movne \divisor, \divisor, lsr #4
+ bne 1b
+
+.endm
+
+
+.macro ARM_DIV2_ORDER divisor, order
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz \order, \divisor
+ rsb \order, \order, #31
+
+#else
+
+ cmp \divisor, #(1 << 16)
+ movhs \divisor, \divisor, lsr #16
+ movhs \order, #16
+ movlo \order, #0
+
+ cmp \divisor, #(1 << 8)
+ movhs \divisor, \divisor, lsr #8
+ addhs \order, \order, #8
+
+ cmp \divisor, #(1 << 4)
+ movhs \divisor, \divisor, lsr #4
+ addhs \order, \order, #4
+
+ cmp \divisor, #(1 << 2)
+ addhi \order, \order, #3
+ addls \order, \order, \divisor, lsr #1
+
+#endif
+
+.endm
+
+
+.macro ARM_MOD_BODY dividend, divisor, order, spare
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz \order, \divisor
+ clz \spare, \dividend
+ sub \order, \order, \spare
+ mov \divisor, \divisor, lsl \order
+
+#else
+
+ mov \order, #0
+
+ @ Unless the divisor is very big, shift it up in multiples of
+ @ four bits, since this is the amount of unwinding in the main
+ @ division loop. Continue shifting until the divisor is
+ @ larger than the dividend.
+1: cmp \divisor, #0x10000000
+ cmplo \divisor, \dividend
+ movlo \divisor, \divisor, lsl #4
+ addlo \order, \order, #4
+ blo 1b
+
+ @ For very big divisors, we must shift it a bit at a time, or
+ @ we will be in danger of overflowing.
+1: cmp \divisor, #0x80000000
+ cmplo \divisor, \dividend
+ movlo \divisor, \divisor, lsl #1
+ addlo \order, \order, #1
+ blo 1b
+
+#endif
+
+ @ Perform all needed substractions to keep only the reminder.
+ @ Do comparisons in batch of 4 first.
+ subs \order, \order, #3 @ yes, 3 is intended here
+ blt 2f
+
+1: cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+ cmp \dividend, \divisor, lsr #1
+ subhs \dividend, \dividend, \divisor, lsr #1
+ cmp \dividend, \divisor, lsr #2
+ subhs \dividend, \dividend, \divisor, lsr #2
+ cmp \dividend, \divisor, lsr #3
+ subhs \dividend, \dividend, \divisor, lsr #3
+ cmp \dividend, #1
+ mov \divisor, \divisor, lsr #4
+ subges \order, \order, #4
+ bge 1b
+
+ tst \order, #3
+ teqne \dividend, #0
+ beq 5f
+
+ @ Either 1, 2 or 3 comparison/substractions are left.
+2: cmn \order, #2
+ blt 4f
+ beq 3f
+ cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+ mov \divisor, \divisor, lsr #1
+3: cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+ mov \divisor, \divisor, lsr #1
+4: cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+5:
+.endm
+
+
+ENTRY(__udivsi3)
+ENTRY(__aeabi_uidiv)
+
+ subs r2, r1, #1
+ moveq pc, lr
+ bcc Ldiv0
+ cmp r0, r1
+ bls 11f
+ tst r1, r2
+ beq 12f
+
+ ARM_DIV_BODY r0, r1, r2, r3
+
+ mov r0, r2
+ mov pc, lr
+
+11: moveq r0, #1
+ movne r0, #0
+ mov pc, lr
+
+12: ARM_DIV2_ORDER r1, r2
+
+ mov r0, r0, lsr r2
+ mov pc, lr
+
+
+ENTRY(__umodsi3)
+
+ subs r2, r1, #1 @ compare divisor with 1
+ bcc Ldiv0
+ cmpne r0, r1 @ compare dividend with divisor
+ moveq r0, #0
+ tsthi r1, r2 @ see if divisor is power of 2
+ andeq r0, r0, r2
+ movls pc, lr
+
+ ARM_MOD_BODY r0, r1, r2, r3
+
+ mov pc, lr
+
+
+ENTRY(__divsi3)
+ENTRY(__aeabi_idiv)
+
+ cmp r1, #0
+ eor ip, r0, r1 @ save the sign of the result.
+ beq Ldiv0
+ rsbmi r1, r1, #0 @ loops below use unsigned.
+ subs r2, r1, #1 @ division by 1 or -1 ?
+ beq 10f
+ movs r3, r0
+ rsbmi r3, r0, #0 @ positive dividend value
+ cmp r3, r1
+ bls 11f
+ tst r1, r2 @ divisor is power of 2 ?
+ beq 12f
+
+ ARM_DIV_BODY r3, r1, r0, r2
+
+ cmp ip, #0
+ rsbmi r0, r0, #0
+ mov pc, lr
+
+10: teq ip, r0 @ same sign ?
+ rsbmi r0, r0, #0
+ mov pc, lr
+
+11: movlo r0, #0
+ moveq r0, ip, asr #31
+ orreq r0, r0, #1
+ mov pc, lr
+
+12: ARM_DIV2_ORDER r1, r2
+
+ cmp ip, #0
+ mov r0, r3, lsr r2
+ rsbmi r0, r0, #0
+ mov pc, lr
+
+
+ENTRY(__modsi3)
+
+ cmp r1, #0
+ beq Ldiv0
+ rsbmi r1, r1, #0 @ loops below use unsigned.
+ movs ip, r0 @ preserve sign of dividend
+ rsbmi r0, r0, #0 @ if negative make positive
+ subs r2, r1, #1 @ compare divisor with 1
+ cmpne r0, r1 @ compare dividend with divisor
+ moveq r0, #0
+ tsthi r1, r2 @ see if divisor is power of 2
+ andeq r0, r0, r2
+ bls 10f
+
+ ARM_MOD_BODY r0, r1, r2, r3
+
+10: cmp ip, #0
+ rsbmi r0, r0, #0
+ mov pc, lr
+
+ENTRY(__aeabi_uidivmod)
+
+ stmfd sp!, {r0, r1, ip, lr}
+ bl __aeabi_uidiv
+ ldmfd sp!, {r1, r2, ip, lr}
+ mul r3, r0, r2
+ sub r1, r1, r3
+ mov pc, lr
+
+ENTRY(__aeabi_idivmod)
+
+ stmfd sp!, {r0, r1, ip, lr}
+ bl __aeabi_idiv
+ ldmfd sp!, {r1, r2, ip, lr}
+ mul r3, r0, r2
+ sub r1, r1, r3
+ mov pc, lr
+
+Ldiv0:
+
+ str lr, [sp, #-8]!
+ bl __div0
+ mov r0, #0 @ About as wrong as it could be.
+ ldr pc, [sp], #8
+
+ENTRY(__div0)
+ mov pc, lr
diff --git a/src/target/firmware/lib/memcpy.S b/src/target/firmware/lib/memcpy.S
new file mode 100644
index 00000000..2bbd5692
--- /dev/null
+++ b/src/target/firmware/lib/memcpy.S
@@ -0,0 +1,59 @@
+/*
+ * linux/arch/arm/lib/memcpy.S
+ *
+ * Author: Nicolas Pitre
+ * Created: Sep 28, 2005
+ * Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+
+ .macro ldr1w ptr reg abort
+ ldr \reg, [\ptr], #4
+ .endm
+
+ .macro ldr4w ptr reg1 reg2 reg3 reg4 abort
+ ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
+ .endm
+
+ .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+ .endm
+
+ .macro ldr1b ptr reg cond=al abort
+ ldr\cond\()b \reg, [\ptr], #1
+ .endm
+
+ .macro str1w ptr reg abort
+ str \reg, [\ptr], #4
+ .endm
+
+ .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+ .endm
+
+ .macro str1b ptr reg cond=al abort
+ str\cond\()b \reg, [\ptr], #1
+ .endm
+
+ .macro enter reg1 reg2
+ stmdb sp!, {r0, \reg1, \reg2}
+ .endm
+
+ .macro exit reg1 reg2
+ ldmfd sp!, {r0, \reg1, \reg2}
+ .endm
+
+ .text
+
+/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
+
+ENTRY(memcpy)
+
+#include "copy_template.S"
+
diff --git a/src/target/firmware/lib/memset.S b/src/target/firmware/lib/memset.S
new file mode 100644
index 00000000..04e254a8
--- /dev/null
+++ b/src/target/firmware/lib/memset.S
@@ -0,0 +1,80 @@
+/*
+ * linux/arch/arm/lib/memset.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ASM optimised string functions
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+
+ .text
+ .align 5
+ .word 0
+
+1: subs r2, r2, #4 @ 1 do we have enough
+ blt 5f @ 1 bytes to align with?
+ cmp r3, #2 @ 1
+ strltb r1, [r0], #1 @ 1
+ strleb r1, [r0], #1 @ 1
+ strb r1, [r0], #1 @ 1
+ add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
+/*
+ * The pointer is now aligned and the length is adjusted. Try doing the
+ * memzero again.
+ */
+
+ENTRY(memset)
+ ands r3, r0, #3 @ 1 unaligned?
+ bne 1b @ 1
+/*
+ * we know that the pointer in r0 is aligned to a word boundary.
+ */
+ orr r1, r1, r1, lsl #8
+ orr r1, r1, r1, lsl #16
+ mov r3, r1
+ cmp r2, #16
+ blt 4f
+/*
+ * We need an extra register for this loop - save the return address and
+ * use the LR
+ */
+ str lr, [sp, #-4]!
+ mov ip, r1
+ mov lr, r1
+
+2: subs r2, r2, #64
+ stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
+ stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia r0!, {r1, r3, ip, lr}
+ bgt 2b
+ LOADREGS(eqfd, sp!, {pc}) @ Now <64 bytes to go.
+/*
+ * No need to correct the count; we're only testing bits from now on
+ */
+ tst r2, #32
+ stmneia r0!, {r1, r3, ip, lr}
+ stmneia r0!, {r1, r3, ip, lr}
+ tst r2, #16
+ stmneia r0!, {r1, r3, ip, lr}
+ ldr lr, [sp], #4
+
+4: tst r2, #8
+ stmneia r0!, {r1, r3}
+ tst r2, #4
+ strne r1, [r0], #4
+/*
+ * When we get here, we've got less than 4 bytes to zero. We
+ * may have an unaligned pointer as well.
+ */
+5: tst r2, #2
+ strneb r1, [r0], #1
+ strneb r1, [r0], #1
+ tst r2, #1
+ strneb r1, [r0], #1
+ RETINSTR(mov,pc,lr)
diff --git a/src/target/firmware/lib/printf.c b/src/target/firmware/lib/printf.c
new file mode 100644
index 00000000..a4fc6876
--- /dev/null
+++ b/src/target/firmware/lib/printf.c
@@ -0,0 +1,19 @@
+
+#include <stdio.h>
+#include <stdarg.h>
+
+static char printf_buffer[1024];
+
+int printf(const char *fmt, ...)
+{
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+ r = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, args);
+ va_end(args);
+
+ puts(printf_buffer);
+
+ return r;
+}
diff --git a/src/target/firmware/lib/setbit.S b/src/target/firmware/lib/setbit.S
new file mode 100644
index 00000000..9009bc1e
--- /dev/null
+++ b/src/target/firmware/lib/setbit.S
@@ -0,0 +1,22 @@
+/*
+ * linux/arch/arm/lib/setbit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+/*
+ * Purpose : Function to set a bit
+ * Prototype: int set_bit(int bit, void *addr)
+ */
+ENTRY(_set_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_set_bit_le)
+ bitop orr
diff --git a/src/target/firmware/lib/string.c b/src/target/firmware/lib/string.c
new file mode 100644
index 00000000..97036528
--- /dev/null
+++ b/src/target/firmware/lib/string.c
@@ -0,0 +1,50 @@
+/*
+ * linux/lib/string.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * - Added strsep() which will replace strtok() soon (because strsep() is
+ * reentrant and should be faster). Use only strsep() in new code, please.
+ *
+ * * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
+ * Matthew Hawkins <matt@mh.dropbear.id.au>
+ * - Kissed strtok() goodbye
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <ctype.h>
+
+
+#ifndef __HAVE_ARCH_STRNLEN
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char *s, size_t count)
+{
+ const char *sc;
+
+ for (sc = s; count-- && *sc != '\0'; ++sc)
+ /* nothing */;
+ return sc - s;
+}
+#endif
+
+size_t strlen(const char *s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; ++sc)
+ /* nothing */;
+ return sc - s;
+}
diff --git a/src/target/firmware/lib/testchangebit.S b/src/target/firmware/lib/testchangebit.S
new file mode 100644
index 00000000..37c303e3
--- /dev/null
+++ b/src/target/firmware/lib/testchangebit.S
@@ -0,0 +1,18 @@
+/*
+ * linux/arch/arm/lib/testchangebit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+ENTRY(_test_and_change_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_test_and_change_bit_le)
+ testop eor, strb
diff --git a/src/target/firmware/lib/testclearbit.S b/src/target/firmware/lib/testclearbit.S
new file mode 100644
index 00000000..985c3996
--- /dev/null
+++ b/src/target/firmware/lib/testclearbit.S
@@ -0,0 +1,18 @@
+/*
+ * linux/arch/arm/lib/testclearbit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+ENTRY(_test_and_clear_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_test_and_clear_bit_le)
+ testop bicne, strneb
diff --git a/src/target/firmware/lib/testsetbit.S b/src/target/firmware/lib/testsetbit.S
new file mode 100644
index 00000000..4a8a164b
--- /dev/null
+++ b/src/target/firmware/lib/testsetbit.S
@@ -0,0 +1,18 @@
+/*
+ * linux/arch/arm/lib/testsetbit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+ENTRY(_test_and_set_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_test_and_set_bit_le)
+ testop orreq, streqb
diff --git a/src/target/firmware/lib/vsprintf.c b/src/target/firmware/lib/vsprintf.c
new file mode 100644
index 00000000..80e8c1ad
--- /dev/null
+++ b/src/target/firmware/lib/vsprintf.c
@@ -0,0 +1,847 @@
+/*
+ * linux/lib/vsprintf.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+/*
+ * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ * - changed to provide snprintf and vsnprintf functions
+ * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
+ * - scnprintf and vscnprintf
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <asm/div64.h>
+
+/**
+ * strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long strtoul(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long result = 0,value;
+
+ if (!base) {
+ base = 10;
+ if (*cp == '0') {
+ base = 8;
+ cp++;
+ if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+ cp++;
+ base = 16;
+ }
+ }
+ } else if (base == 16) {
+ if (cp[0] == '0' && toupper(cp[1]) == 'X')
+ cp += 2;
+ }
+ while (isxdigit(*cp) &&
+ (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
+
+
+/**
+ * strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long strtol(const char *cp,char **endp,unsigned int base)
+{
+ if(*cp=='-')
+ return -strtoul(cp+1,endp,base);
+ return strtoul(cp,endp,base);
+}
+
+
+/**
+ * strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long strtoull(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long long result = 0,value;
+
+ if (!base) {
+ base = 10;
+ if (*cp == '0') {
+ base = 8;
+ cp++;
+ if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+ cp++;
+ base = 16;
+ }
+ }
+ } else if (base == 16) {
+ if (cp[0] == '0' && toupper(cp[1]) == 'X')
+ cp += 2;
+ }
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
+
+
+/**
+ * strtoll - convert a string to a signed long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long long strtoll(const char *cp,char **endp,unsigned int base)
+{
+ if(*cp=='-')
+ return -strtoull(cp+1,endp,base);
+ return strtoull(cp,endp,base);
+}
+
+static int skip_atoi(const char **s)
+{
+ int i=0;
+
+ while (isdigit(**s))
+ i = i*10 + *((*s)++) - '0';
+ return i;
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
+{
+ char c,sign,tmp[66];
+ const char *digits;
+ static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ int i;
+
+ digits = (type & LARGE) ? large_digits : small_digits;
+ if (type & LEFT)
+ type &= ~ZEROPAD;
+ if (base < 2 || base > 36)
+ return NULL;
+ c = (type & ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & SIGN) {
+ if ((signed long long) num < 0) {
+ sign = '-';
+ num = - (signed long long) num;
+ size--;
+ } else if (type & PLUS) {
+ sign = '+';
+ size--;
+ } else if (type & SPACE) {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++]='0';
+ else while (num != 0)
+ tmp[i++] = digits[do_div(num,base)];
+ if (i > precision)
+ precision = i;
+ size -= precision;
+ if (!(type&(ZEROPAD+LEFT))) {
+ while(size-->0) {
+ if (buf <= end)
+ *buf = ' ';
+ ++buf;
+ }
+ }
+ if (sign) {
+ if (buf <= end)
+ *buf = sign;
+ ++buf;
+ }
+ if (type & SPECIAL) {
+ if (base==8) {
+ if (buf <= end)
+ *buf = '0';
+ ++buf;
+ } else if (base==16) {
+ if (buf <= end)
+ *buf = '0';
+ ++buf;
+ if (buf <= end)
+ *buf = digits[33];
+ ++buf;
+ }
+ }
+ if (!(type & LEFT)) {
+ while (size-- > 0) {
+ if (buf <= end)
+ *buf = c;
+ ++buf;
+ }
+ }
+ while (i < precision--) {
+ if (buf <= end)
+ *buf = '0';
+ ++buf;
+ }
+ while (i-- > 0) {
+ if (buf <= end)
+ *buf = tmp[i];
+ ++buf;
+ }
+ while (size-- > 0) {
+ if (buf <= end)
+ *buf = ' ';
+ ++buf;
+ }
+ return buf;
+}
+
+/**
+ * vsnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which would
+ * be generated for the given input, excluding the trailing
+ * '\0', as per ISO C99. If you want to have the exact
+ * number of characters written into @buf as return value
+ * (not including the trailing '\0'), use vscnprintf. If the
+ * return is greater than or equal to @size, the resulting
+ * string is truncated.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf instead.
+ */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ int len;
+ unsigned long long num;
+ int i, base;
+ char *str, *end, c;
+ const char *s;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+ /* 'z' support added 23/7/1999 S.H. */
+ /* 'z' changed to 'Z' --davidm 1/25/99 */
+ /* 't' added for ptrdiff_t */
+
+ /* Reject out-of-range values early */
+ if ((int) size < 0) {
+ return 0;
+ }
+
+ str = buf;
+ end = buf + size - 1;
+
+ if (end < buf - 1) {
+ end = ((void *) -1);
+ size = end - buf + 1;
+ }
+
+ for (; *fmt ; ++fmt) {
+ if (*fmt != '%') {
+ if (str <= end)
+ *str = *fmt;
+ ++str;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+ repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt) {
+ case '-': flags |= LEFT; goto repeat;
+ case '+': flags |= PLUS; goto repeat;
+ case ' ': flags |= SPACE; goto repeat;
+ case '#': flags |= SPECIAL; goto repeat;
+ case '0': flags |= ZEROPAD; goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ field_width = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (isdigit(*fmt))
+ precision = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+ *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
+ qualifier = *fmt;
+ ++fmt;
+ if (qualifier == 'l' && *fmt == 'l') {
+ qualifier = 'L';
+ ++fmt;
+ }
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt) {
+ case 'c':
+ if (!(flags & LEFT)) {
+ while (--field_width > 0) {
+ if (str <= end)
+ *str = ' ';
+ ++str;
+ }
+ }
+ c = (unsigned char) va_arg(args, int);
+ if (str <= end)
+ *str = c;
+ ++str;
+ while (--field_width > 0) {
+ if (str <= end)
+ *str = ' ';
+ ++str;
+ }
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+
+ len = strnlen(s, precision);
+
+ if (!(flags & LEFT)) {
+ while (len < field_width--) {
+ if (str <= end)
+ *str = ' ';
+ ++str;
+ }
+ }
+ for (i = 0; i < len; ++i) {
+ if (str <= end)
+ *str = *s;
+ ++str; ++s;
+ }
+ while (len < field_width--) {
+ if (str <= end)
+ *str = ' ';
+ ++str;
+ }
+ continue;
+
+ case 'p':
+ if (field_width == -1) {
+ field_width = 2*sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ str = number(str, end,
+ (unsigned long) va_arg(args, void *),
+ 16, field_width, precision, flags);
+ continue;
+
+
+ case 'n':
+ /* FIXME:
+ * What does C99 say about the overflow case here? */
+ if (qualifier == 'l') {
+ long * ip = va_arg(args, long *);
+ *ip = (str - buf);
+ } else if (qualifier == 'Z' || qualifier == 'z') {
+ size_t * ip = va_arg(args, size_t *);
+ *ip = (str - buf);
+ } else {
+ int * ip = va_arg(args, int *);
+ *ip = (str - buf);
+ }
+ continue;
+
+ case '%':
+ if (str <= end)
+ *str = '%';
+ ++str;
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+
+ default:
+ if (str <= end)
+ *str = '%';
+ ++str;
+ if (*fmt) {
+ if (str <= end)
+ *str = *fmt;
+ ++str;
+ } else {
+ --fmt;
+ }
+ continue;
+ }
+ if (qualifier == 'L')
+ num = va_arg(args, long long);
+ else if (qualifier == 'l') {
+ num = va_arg(args, unsigned long);
+ if (flags & SIGN)
+ num = (signed long) num;
+ } else if (qualifier == 'Z' || qualifier == 'z') {
+ num = va_arg(args, size_t);
+ } else if (qualifier == 't') {
+ num = va_arg(args, long);
+ } else if (qualifier == 'h') {
+ num = (unsigned short) va_arg(args, int);
+ if (flags & SIGN)
+ num = (signed short) num;
+ } else {
+ num = va_arg(args, unsigned int);
+ if (flags & SIGN)
+ num = (signed int) num;
+ }
+ str = number(str, end, num, base,
+ field_width, precision, flags);
+ }
+ if (str <= end)
+ *str = '\0';
+ else if (size > 0)
+ /* don't write out a null byte if the buf size is zero */
+ *end = '\0';
+ /* the trailing null byte doesn't count towards the total
+ * ++str;
+ */
+ return str-buf;
+}
+
+
+/**
+ * vscnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which have been written into
+ * the @buf not including the trailing '\0'. If @size is <= 0 the function
+ * returns 0.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want scnprintf instead.
+ */
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ unsigned int i;
+
+ i=vsnprintf(buf,size,fmt,args);
+ return (i >= size) ? (size - 1) : i;
+}
+
+
+/**
+ * snprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing null,
+ * as per ISO C99. If the return is greater than or equal to
+ * @size, the resulting string is truncated.
+ */
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i=vsnprintf(buf,size,fmt,args);
+ va_end(args);
+ return i;
+}
+
+
+/**
+ * scnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters written into @buf not including
+ * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
+ * greater than or equal to @size, the resulting string is truncated.
+ */
+
+int scnprintf(char * buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ unsigned int i;
+
+ va_start(args, fmt);
+ i = vsnprintf(buf, size, fmt, args);
+ va_end(args);
+ return (i >= size) ? (size - 1) : i;
+}
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use vsnprintf or vscnprintf in order to avoid
+ * buffer overflows.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ return vsnprintf(buf, INT_MAX, fmt, args);
+}
+
+
+/**
+ * sprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use snprintf or scnprintf in order to avoid
+ * buffer overflows.
+ */
+int sprintf(char * buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i=vsnprintf(buf, INT_MAX, fmt, args);
+ va_end(args);
+ return i;
+}
+
+
+/**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf: input buffer
+ * @fmt: format of buffer
+ * @args: arguments
+ */
+int vsscanf(const char * buf, const char * fmt, va_list args)
+{
+ const char *str = buf;
+ char *next;
+ char digit;
+ int num = 0;
+ int qualifier;
+ int base;
+ int field_width;
+ int is_sign = 0;
+
+ while(*fmt && *str) {
+ /* skip any white space in format */
+ /* white space in format matchs any amount of
+ * white space, including none, in the input.
+ */
+ if (isspace(*fmt)) {
+ while (isspace(*fmt))
+ ++fmt;
+ while (isspace(*str))
+ ++str;
+ }
+
+ /* anything that is not a conversion must match exactly */
+ if (*fmt != '%' && *fmt) {
+ if (*fmt++ != *str++)
+ break;
+ continue;
+ }
+
+ if (!*fmt)
+ break;
+ ++fmt;
+
+ /* skip this conversion.
+ * advance both strings to next white space
+ */
+ if (*fmt == '*') {
+ while (!isspace(*fmt) && *fmt)
+ fmt++;
+ while (!isspace(*str) && *str)
+ str++;
+ continue;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ field_width = skip_atoi(&fmt);
+
+ /* get conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+ *fmt == 'Z' || *fmt == 'z') {
+ qualifier = *fmt++;
+ if (qualifier == *fmt) {
+ if (qualifier == 'h') {
+ qualifier = 'H';
+ fmt++;
+ } else if (qualifier == 'l') {
+ qualifier = 'L';
+ fmt++;
+ }
+ }
+ }
+ base = 10;
+ is_sign = 0;
+
+ if (!*fmt || !*str)
+ break;
+
+ switch(*fmt++) {
+ case 'c':
+ {
+ char *s = (char *) va_arg(args,char*);
+ if (field_width == -1)
+ field_width = 1;
+ do {
+ *s++ = *str++;
+ } while (--field_width > 0 && *str);
+ num++;
+ }
+ continue;
+ case 's':
+ {
+ char *s = (char *) va_arg(args, char *);
+ if(field_width == -1)
+ field_width = INT_MAX;
+ /* first, skip leading white space in buffer */
+ while (isspace(*str))
+ str++;
+
+ /* now copy until next white space */
+ while (*str && !isspace(*str) && field_width--) {
+ *s++ = *str++;
+ }
+ *s = '\0';
+ num++;
+ }
+ continue;
+ case 'n':
+ /* return number of characters read so far */
+ {
+ int *i = (int *)va_arg(args,int*);
+ *i = str - buf;
+ }
+ continue;
+ case 'o':
+ base = 8;
+ break;
+ case 'x':
+ case 'X':
+ base = 16;
+ break;
+ case 'i':
+ base = 0;
+ case 'd':
+ is_sign = 1;
+ case 'u':
+ break;
+ case '%':
+ /* looking for '%' in str */
+ if (*str++ != '%')
+ return num;
+ continue;
+ default:
+ /* invalid format; stop here */
+ return num;
+ }
+
+ /* have some sort of integer conversion.
+ * first, skip white space in buffer.
+ */
+ while (isspace(*str))
+ str++;
+
+ digit = *str;
+ if (is_sign && digit == '-')
+ digit = *(str + 1);
+
+ if (!digit
+ || (base == 16 && !isxdigit(digit))
+ || (base == 10 && !isdigit(digit))
+ || (base == 8 && (!isdigit(digit) || digit > '7'))
+ || (base == 0 && !isdigit(digit)))
+ break;
+
+ switch(qualifier) {
+ case 'H': /* that's 'hh' in format */
+ if (is_sign) {
+ signed char *s = (signed char *) va_arg(args,signed char *);
+ *s = (signed char) strtol(str,&next,base);
+ } else {
+ unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
+ *s = (unsigned char) strtoul(str, &next, base);
+ }
+ break;
+ case 'h':
+ if (is_sign) {
+ short *s = (short *) va_arg(args,short *);
+ *s = (short) strtol(str,&next,base);
+ } else {
+ unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
+ *s = (unsigned short) strtoul(str, &next, base);
+ }
+ break;
+ case 'l':
+ if (is_sign) {
+ long *l = (long *) va_arg(args,long *);
+ *l = strtol(str,&next,base);
+ } else {
+ unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
+ *l = strtoul(str,&next,base);
+ }
+ break;
+ case 'L':
+ if (is_sign) {
+ long long *l = (long long*) va_arg(args,long long *);
+ *l = strtoll(str,&next,base);
+ } else {
+ unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
+ *l = strtoull(str,&next,base);
+ }
+ break;
+ case 'Z':
+ case 'z':
+ {
+ size_t *s = (size_t*) va_arg(args,size_t*);
+ *s = (size_t) strtoul(str,&next,base);
+ }
+ break;
+ default:
+ if (is_sign) {
+ int *i = (int *) va_arg(args, int*);
+ *i = (int) strtol(str,&next,base);
+ } else {
+ unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
+ *i = (unsigned int) strtoul(str,&next,base);
+ }
+ break;
+ }
+ num++;
+
+ if (!next)
+ break;
+ str = next;
+ }
+ return num;
+}
+
+
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf: input buffer
+ * @fmt: formatting of buffer
+ * @...: resulting arguments
+ */
+int sscanf(const char * buf, const char * fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args,fmt);
+ i = vsscanf(buf,fmt,args);
+ va_end(args);
+ return i;
+}
+
+/* generic puts() implementation independent of who provides putchar() */
+int puts(const char *s)
+{
+#ifdef ARCH_HAS_CONSOLE
+ return _puts(s);
+#else
+ while (1) {
+ char c = *s++;
+ if (c == 0)
+ return;
+ putchar(c);
+ }
+ return 0;
+#endif
+}
diff --git a/src/target/firmware/rf/mt6139.c b/src/target/firmware/rf/mt6139.c
new file mode 100644
index 00000000..d48e6529
--- /dev/null
+++ b/src/target/firmware/rf/mt6139.c
@@ -0,0 +1,205 @@
+/* Driver for RF Transceiver Circuit (MT6139) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <keypad.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <layer1/agc.h>
+#include <rffe.h>
+
+#include <mtk/mt6139.h>
+
+static void mt6139_compute_pll(uint32_t f_vco_100khz,
+ uint16_t *nint, uint16_t *nfrac)
+{
+ /* To compute Nint, we assume Nfrac is zero */
+ *nint = (fvco_100khz / (10 * 2 * 26)) - (0 / 130);
+
+ if (*nint > 127)
+ printf("VCO Frequency %u kHz is out of spec\n", f_vco_100khz);
+
+ /* Compute Nfract using the pre-computed Nint */
+ /* Nfrac = ( (Fvco/2*26) - Nint) * 130 */
+ /* Nfrac = ( (Fvco*130)/(2*26) - (Nint * 130) */
+ *nfrac = (f_vco_100khz*130)/(52*10) - (*nint * 130);
+}
+
+/* Set ARFCN. Takes 2 reg_write, i.e. 8 TPU instructions */
+void mt6139_set_arfcn(uint16_t arfcn, int uplink)
+{
+ uint32_t regval = 0;
+ uint32_t vco_mult;
+ uint32_t freq_khz, f_vco_100khz;
+ uint16_t nint, nfrac;
+
+ freq_khz = gsm_arfcn2freq10(arfcn, uplink) * 100;
+ printd("ARFCN %u -> %u kHz\n", arfcn, freq_khz);
+
+ switch (gsm_arfcn2band(arfcn)) {
+ case GSM_BAND_850:
+ if (uplink)
+ regval |= MT6139_CW1_TRX_850;
+ regval |= (0 << MT6139_CW1_BAND_SHIFT);
+ vco_mult = 4;
+ break;
+ case GSM_BAND_900:
+ regval |= (1 << MT6139_CW1_BAND_SHIFT);
+ vco_mult = 4;
+ break;
+ case GSM_BAND_1800:
+ regval |= (2 << MT6139_CW1_BAND_SHIFT);
+ vco_mult = 2;
+ break;
+ case GSM_BAND_1900:
+ regval |= (3 << MT6139_CW1_BAND_SHIFT);
+ vco_mult = 2;
+ break;
+ default:
+ printf("Unsupported rf_band.\n");
+ break;
+ }
+
+ /* Compute VCO frequency for channel frequency */
+ f_vco_100khz = (freq_khz / 100) * vco_mult;
+
+ /* Compute Nint and Nfract */
+ mt6139_compute_pll(f_vco_100khz, &nint, &nfrac);
+
+ /* mask-in the Nint / Nfrac bits in CW1 */
+ regval |= (nfrac & 0xff) << MT6139_CW1_NFRACT_SHIFT;
+ regval |= (nint & 0x7f) << MT6139_CW1_NINT_SHIFT;
+
+}
+
+void mt6139_init()
+{
+ uint32_t val;
+
+ /* reset and get it out of reset again */
+ val = MT6139_CW0_DIEN | (0x20 << MT6139_CW0_AFC_SHIFT);
+ mt6139_reg_write(0, val | MT6139_CW0_POR);
+ mt6139_reg_write(0, val);
+
+ /* Turn off AM and A loop calibration function (CM9) */
+ val = (0x40 << MT6139_CW9_DCD_CQ_SHIFT) |
+ (0x40 << MT6139_CW9_DCD_BQ_SHIFT) |
+ MT6139_CW9_PWR_DAC_C | MT6139_CW9_PWR_DAC_B;
+ mt6139_reg_write(9, val);
+
+ /* Move to SLEEP mode */
+ val = (0x3e << MT6139_CW2_GAINTBL_SHIFT) |
+ (MODE_SLEEP << MT6139_CW2_MODE_SHIFT) |
+ MT6139_CW2_AUTO_CAL |
+ (0x20 << MT6139_CW2_DCD_AQ_SHIFT) |
+ (0x20 << MT6139_CW2_DCD_AI_SHIFT);
+ mt6139_reg_write(2, val);
+}
+
+void mt6139_rx_burst()
+{
+ uint8_t pga_gain;
+
+ /* Turn on the synthesizer and move into Warm-up mode */
+ val = (0x3e << MT6139_CW2_GAINTBL_SHIFT) |
+ (MODE_WARM_UP << MT6139_CW2_MODE_SHIFT) |
+ MT6139_CW2_AUTO_CAL |
+ (0x20 << MT6139_CW2_DCD_AQ_SHIFT) |
+ (0x20 << MT6139_CW2_DCD_AI_SHIFT);
+ mt6139_reg_write(2, val);
+
+ /* Program the frequency synthesizer N counter and band selection */
+ /* FIXME: see above for mt6139_set_arfcn() */
+
+ /* Set receive mode, PGA gain */
+ val = (pga_gain << MT6139_CW2_GAINTBL_SHIFT) |
+ (MODE_RECEIVE << MT6139_CW2_MODE_SHIFT) |
+ MT6139_CW2_AUTO_CAL |
+ (0x20 << MT6139_CW2_DCD_AQ_SHIFT) |
+ (0x20 << MT6139_CW2_DCD_AI_SHIFT);
+ mt6139_reg_write(2, val);
+
+ /* FIXME: Do the actual burst Rx */
+
+ /* Set Sleep mode */
+ val = (0x3e << MT6139_CW2_GAINTBL_SHIFT) |
+ (MODE_SLEEP << MT6139_CW2_MODE_SHIFT) |
+ MT6139_CW2_AUTO_CAL |
+ (0x20 << MT6139_CW2_DCD_AQ_SHIFT) |
+ (0x20 << MT6139_CW2_DCD_AI_SHIFT);
+ mt6139_reg_write(2, val);
+}
+
+void mt6139_tx_burst()
+{
+ /* Turn on the synthesizer and move into Warm-up mode */
+ val = (0x3e << MT6139_CW2_GAINTBL_SHIFT) |
+ (MODE_WARM_UP << MT6139_CW2_MODE_SHIFT) |
+ MT6139_CW2_AUTO_CAL |
+ (0x20 << MT6139_CW2_DCD_AQ_SHIFT) |
+ (0x20 << MT6139_CW2_DCD_AI_SHIFT);
+ mt6139_reg_write(2, val);
+
+ /* Program the frequency synthesizer N counter and band selection */
+ /* FIXME: see above for mt6139_set_arfcn() */
+
+ /* Send Tx setting */
+ val = MT6139_CW11_TX_CTL |
+ MT6139_CW11_TXG_IQM |
+ MT6139_CW11_TXD_IQM |
+ MT6139_CW11_TX_DIV2 |
+ MT6139_CW11_TX_DIV4 |
+ MT6139_CW11_TXG_BUF |
+ MT6139_CW11_TXD_BUF |
+ (3 << MT6139_CW11_TX_FLT_SHIFT) |
+ (1 << MT6139_CW11_TXAPC_SHIFT) |
+ (3 << MT6139_CW11_TXPW_SHIFT) |
+ (2 << MT6139_CW11_TXBIAST_SHIFT) |
+ MT6139_CW11_TXDIV_GC0;
+ if (1) // low band
+ mt6139_reg_write(11, val | (0 << MT6139_CW11_TXMODGAIN_SHIFT));
+ else
+ mt6139_reg_write(11, val | (4 << MT6139_CW11_TXMODGAIN_SHIFT));
+
+ /* Set Transmit mode */
+ val = (0x3e << MT6139_CW2_GAINTBL_SHIFT) |
+ (MODE_TRANSMIT << MT6139_CW2_MODE_SHIFT) |
+ MT6139_CW2_AUTO_CAL |
+ (0x20 << MT6139_CW2_DCD_AQ_SHIFT) |
+ (0x20 << MT6139_CW2_DCD_AI_SHIFT);
+ mt6139_reg_write(2, val);
+
+ /* FIXME: Do the actual burst Tx */
+
+ /* Set Sleep mode */
+ val = (0x3e << MT6139_CW2_GAINTBL_SHIFT) |
+ (MODE_SLEEP << MT6139_CW2_MODE_SHIFT) |
+ MT6139_CW2_AUTO_CAL |
+ (0x20 << MT6139_CW2_DCD_AQ_SHIFT) |
+ (0x20 << MT6139_CW2_DCD_AI_SHIFT);
+ mt6139_reg_write(2, val);
+}
+
diff --git a/src/target/firmware/rf/trf6151.c b/src/target/firmware/rf/trf6151.c
new file mode 100644
index 00000000..96210fc6
--- /dev/null
+++ b/src/target/firmware/rf/trf6151.c
@@ -0,0 +1,605 @@
+/* Driver for RF Transceiver Circuit (TRF6151) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <keypad.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <layer1/agc.h>
+#include <rffe.h>
+
+#include <rf/trf6151.h>
+
+/* #define WARN_OUT_OF_SPEC 1 */
+
+enum trf6151_reg {
+ REG_RX = 0, /* RF general settings */
+ REG_PLL = 1, /* PLL settings */
+ REG_PWR = 2, /* Power on/off functional blocks */
+ REG_CFG = 3, /* Transceiver and PA controller settings */
+ REG_TEST1 = 4,
+ REG_TEST2 = 5,
+ REG_TEST3 = 6,
+ REG_TEST4 = 7,
+ _MAX_REG
+};
+
+/* REG_RX */
+#define RX_READ_EN (1 << 7)
+#define RX_CAL_MODE (1 << 8)
+#define RX_RF_GAIN_HIGH (3 << 9)
+#define RX_VGA_GAIN_SHIFT 11
+
+/* REG_PWR */
+#define PWR_BANDGAP_SHIFT 3
+#define PWR_BANDGAP_OFF (0 << PWR_BANDGAP_SHIFT)
+#define PWR_BANDGAP_ON_SPEEDUP (2 << PWR_BANDGAP_SHIFT)
+#define PWR_BANDGAP_ON (3 << PWR_BANDGAP_SHIFT)
+#define PWR_REGUL_ON (1 << 5)
+#define PWR_SYNTHE_OFF (0)
+#define PWR_SYNTHE_RX_ON (1 << 9)
+#define PWR_SYNTHE_TX_ON (1 << 10)
+#define PWR_RX_MODE (1 << 11)
+#define PWR_TX_MODE (1 << 13)
+#define PWR_PACTRL_APC (1 << 14)
+#define PWR_PACTRL_APCEN (1 << 15)
+
+/* REG_CFG */
+#define CFG_TX_LOOP_MANU (1 << 3)
+#define CFG_PACTLR_IDIOD_30uA (0 << 4)
+#define CFG_PACTLR_IDIOD_300uA (1 << 4)
+#define CFG_PACTLR_RES_OPEN (0 << 10)
+#define CFG_PACTLR_RES_150k (1 << 10)
+#define CFG_PACTLR_RES_300k (2 << 10)
+#define CFG_PACTLR_CAP_0pF (0 << 12)
+#define CFG_PACTLR_CAP_12p5F (1 << 12)
+#define CFG_PACTLR_CAP_25pF (3 << 12)
+#define CFG_PACTLR_CAP_50pF (2 << 12)
+#define CFG_TEMP_SENSOR (1 << 14)
+#define CFG_ILOGIC_INIT_DIS (1 << 15)
+
+/* FIXME: This must be defined in the RFFE configuration */
+#define TRF6151_TSP_UID 2
+#define TRF6151_PACTRL_CFG (CFG_PACTLR_RES_OPEN|CFG_PACTLR_CAP_0pF|CFG_PACTLR_IDIOD_30uA)
+
+#define PLL_VAL(a, b) ((a << 3) | (((b)-64) << 9))
+
+/* All values in qbits unless otherwise specified */
+#define TRF6151_LDO_DELAY_TS 6 /* six TDMA frames (at least 25ms) */
+#define TRF6151_RX_PLL_DELAY 184 /* 170 us */
+#define TRF6151_TX_PLL_DELAY 260 /* 240 us */
+
+
+enum trf6151_pwr_unit {
+ TRF1651_PACTLR_APC,
+ TRF6151_PACTRL_APCEN,
+ TRF6151_TRANSMITTER,
+ TRF6151_REGULATORS,
+};
+
+enum trf6151_gsm_band {
+ GSM900 = 1,
+ GSM1800 = 2,
+ GSM850_LOW = 4,
+ GSM850_HIGH = 5,
+ GSM1900 = 6,
+};
+
+
+uint16_t rf_arfcn = 871; /* TODO: this needs to be private */
+static uint16_t rf_band;
+
+static uint8_t trf6151_tsp_uid;
+static uint8_t trf6151_vga_dbm = 40;
+static int trf6151_gain_high = 1;
+
+static uint16_t trf6151_reg_cache[_MAX_REG] = {
+ [REG_RX] = 0x9E00,
+ [REG_PLL] = 0x0000,
+ [REG_PWR] = 0x0000,
+ [REG_CFG] = 0x2980,
+};
+
+/* Write to a TRF6151 register (4 TPU instructions) */
+static void trf6151_reg_write(uint16_t reg, uint16_t val)
+{
+ printd("trf6151_reg_write(reg=%u, val=0x%04x)\n", reg, val);
+ /* each TSP write takes 4 TPU instructions */
+ tsp_write(trf6151_tsp_uid, 16, (reg | val));
+ trf6151_reg_cache[reg] = val;
+}
+
+/* Frontend gain can be switched high or low (dB) */
+#define TRF6151_FE_GAIN_LOW 7
+#define TRF6151_FE_GAIN_HIGH 27
+
+/* VGA at baseband can be adjusted in this range (dB) */
+#define TRF6151_VGA_GAIN_MIN 14
+#define TRF6151_VGA_GAIN_MAX 40
+
+/* put current set (or computed) gain to register */
+int trf6151_set_gain_reg(uint8_t dbm, int high)
+{
+ uint16_t reg = trf6151_reg_cache[REG_RX] & 0x07ff;
+ printd("trf6151_set_gain_reg(%u, %d)\n", dbm, high);
+
+ if (dbm < TRF6151_VGA_GAIN_MIN || dbm > TRF6151_VGA_GAIN_MAX)
+ return -1;
+
+ /* clear the gain bits first */
+ reg &= ~((0x1F) << RX_VGA_GAIN_SHIFT);
+ /* OR-in the new gain value */
+ reg |= (6 + (dbm-TRF6151_VGA_GAIN_MIN)/2) << RX_VGA_GAIN_SHIFT;
+
+ if (high)
+ reg |= RX_RF_GAIN_HIGH;
+ else
+ reg &= ~RX_RF_GAIN_HIGH;
+
+ trf6151_reg_write(REG_RX, reg);
+
+ return 0;
+}
+
+int trf6151_set_gain(uint8_t dbm)
+{
+ int high = 0;
+
+ printd("trf6151_set_gain(%u, %d)\n", dbm);
+ /* If this is negative or less than TRF6151_GAIN_MIN, we are pretty
+ * much lost as we cannot reduce the system inherent gain. If it is
+ * positive, it corresponds to the gain that we need to configure */
+ if (dbm < TRF6151_FE_GAIN_LOW + TRF6151_VGA_GAIN_MIN) {
+ printd("AGC Input level overflow\n");
+ trf6151_vga_dbm = TRF6151_VGA_GAIN_MIN;
+ trf6151_gain_high = 0;
+ return 0;
+ } else if (dbm >= TRF6151_FE_GAIN_HIGH + TRF6151_VGA_GAIN_MIN) {
+ high = 1;
+ dbm -= TRF6151_FE_GAIN_HIGH;
+ } else
+ dbm -= TRF6151_FE_GAIN_LOW;
+ if (dbm > TRF6151_VGA_GAIN_MAX)
+ dbm = TRF6151_VGA_GAIN_MAX;
+
+ /* update the static global variables which are used when programming
+ * the window */
+ trf6151_vga_dbm = dbm;
+ trf6151_gain_high = high;
+
+ return 0;
+}
+
+#define SCALE_100KHZ 100
+
+/* Compute TRF6151 PLL valuese */
+static void trf6151_pll_rx(uint32_t freq_khz,
+ uint16_t *pll_config, enum trf6151_gsm_band *band)
+{
+ const uint32_t p=64, r=65;
+ uint32_t freq_100khz, vco_freq_100khz;
+ uint32_t l, n;
+ uint32_t a, b;
+
+ /* Scale into 100kHz unit (avoid overflow in intermediates) */
+ freq_100khz = freq_khz / SCALE_100KHZ;
+
+ /* L selects hi/lo band */
+ l = (freq_khz > 1350000) ? 2 : 4; /* cut at mid point :) */
+
+ /* VCO frequency */
+ vco_freq_100khz = freq_100khz * l;
+
+ /* vco_freq = 26MHz / R * N with R=65 and N=B*P+A */
+ n = (vco_freq_100khz * r) / 260;
+ a = n % p;
+ b = n / p;
+
+ *pll_config = PLL_VAL(a, b);
+
+ /* Out-of-spec tuning warning */
+#ifdef WARN_OUT_OF_SPEC
+ if ((l == 4 && (b < 135 || b > 150)) ||
+ (l == 2 && (b < 141 || b > 155)))
+ printf("Frequency %u kHz is out of spec\n", (unsigned int)freq_khz);
+#endif
+
+ /* Select band */
+ if (l==4) {
+ /* If in the low band, same port for both GSM850/GSM900, so we
+ * choose the best VCO (VCOMAIN1=3.37GHz, VCOMAIN2=3.8GHz) */
+ if (vco_freq_100khz < 35850) /* midpoint */
+ *band = GSM850_LOW;
+ else
+ *band = GSM900;
+
+ /* Out-of-spec freq check */
+#ifdef WARN_OUT_OF_SPEC
+ if (!(freq_khz >= 869000 && freq_khz <= 894000) &&
+ !(freq_khz >= 921000 && freq_khz <= 960000)) /* include GSM-R */
+ printf("Frequency %u outside normal filter range for selected port\n", (unsigned int)freq_khz);
+#endif
+ } else {
+ /* In the high band, different ports for DCS/PCS, so
+ * take what's best and available */
+ /* We're stuck to VCOMAIN2=3.8GHz though ... */
+ uint32_t rx_ports = rffe_get_rx_ports();
+ uint32_t port;
+
+ /* Select port */
+ port = (freq_khz < 1905000) ? (1 << PORT_DCS1800) : (1 << PORT_PCS1900);
+ port = (port & rx_ports) ? port : rx_ports;
+
+ /* Select band */
+ *band = (port & (1 << PORT_DCS1800)) ? GSM1800 : GSM1900;
+
+ /* Out-of-spec freq check */
+#ifdef WARN_OUT_OF_SPEC
+ if ((*band == GSM1800 && (freq_khz < 1805000 || freq_khz > 1880000)) ||
+ (*band == GSM1900 && (freq_khz < 1930000 || freq_khz > 1990000)))
+ printf("Frequency %u outside normal filter range for selected port\n", (unsigned int)freq_khz);
+#endif
+ }
+
+ /* Debug */
+ printd("RX Freq %u kHz => A = %u, B = %u, band = %d, vco_freq = %u kHz\n", freq_khz, a, b, *band, vco_freq_100khz*100);
+
+ /* All done */
+ return;
+}
+
+/* Compute TRF6151 PLL TX values */
+static void trf6151_pll_tx(uint32_t freq_khz,
+ uint16_t *pll_config, enum trf6151_gsm_band *band)
+{
+ const uint32_t p=64;
+ uint32_t r, l, m, m_op_l; /* m_op_l = m +/- l depending on mode */
+ uint32_t freq_100khz;
+ uint32_t n, a, b, b_min, b_max;
+
+ /* Scale into 100kHz unit (avoid overflow in intermediates) */
+ freq_100khz = freq_khz / SCALE_100KHZ;
+
+ /* Select band (and PLL mode) */
+ if (freq_khz > 1350000) {
+ /* High band, so only 1 real PLL mode. band doesn't matter
+ * that much (or at all) but we still do it :p */
+ *band = (freq_khz < 1817500) ? GSM1800 : GSM1900;
+ r = 70;
+ l = 2;
+ m = 26;
+ m_op_l = m + l;
+ b_min = 133;
+ b_max = 149;
+ } else {
+ /* Low band. We have 3 possible PLL modes that output on
+ * the right port: GSM900, GSM850_HIGH, GSM850_LOW.
+ *
+ * The transistion points have been chosen looking at the VCO
+ * and IF frequencies for various frequencies for theses modes
+ */
+ if (freq_khz < 837100) {
+ /* GSM850_LOW */
+ *band = GSM850_LOW;
+ r = 55;
+ l = 4;
+ m = 26;
+ m_op_l = m - l;
+ b_min = 128;
+ b_max = 130;
+ } else if (freq_khz < 850000) {
+ /* GSM850_HIGH */
+ *band = GSM850_HIGH;
+ r = 30;
+ l = 4;
+ m = 52;
+ m_op_l = m - l;
+ b_min = 65;
+ b_max = 66;
+ } else {
+ /* GSM900 */
+ *band = GSM900;
+ r = 35;
+ l = 4;
+ m = 52;
+ m_op_l = m + l;
+ b_min = 68;
+ b_max = 71;
+ }
+ }
+
+ /* vco_freq = f * M * L / (M +- L) */
+ /* = 26MHz / R * N with R=65 and N=B*P+A */
+ n = (freq_100khz * m * l * r) / (m_op_l * 260);
+ a = n % p;
+ b = n / p;
+
+ *pll_config = PLL_VAL(a, b);
+
+ /* Debug */
+ printd("TX Freq %u kHz => A = %u, B = %u, band = %d\n", freq_khz, a, b, *band);
+
+ /* Out-of-spec tuning warning */
+#ifdef WARN_OUT_OF_SPEC
+ if (b < b_min || b > b_max)
+ printf("Frequency %u kHz is out of spec\n", (unsigned int)freq_khz);
+#endif
+
+ /* All done */
+ return;
+}
+
+static inline void trf6151_reset(uint16_t reset_id)
+{
+ /* pull the nRESET line low */
+ tsp_act_disable(reset_id);
+ tpu_enq_wait(50);
+ /* release nRESET */
+ tsp_act_enable(reset_id);
+}
+
+void trf6151_init(uint8_t tsp_uid, uint16_t tsp_reset_id)
+{
+ trf6151_tsp_uid = tsp_uid;
+
+ /* Configure the TSPEN which is connected to TRF6151 STROBE */
+ tsp_setup(trf6151_tsp_uid, 0, 1, 1);
+
+ trf6151_reset(tsp_reset_id);
+
+ /* configure TRF6151 for operation */
+ trf6151_power(1);
+ trf6151_reg_write(REG_CFG, TRF6151_PACTRL_CFG | CFG_ILOGIC_INIT_DIS);
+
+ /* FIXME: Uplink / Downlink Calibration */
+}
+
+void trf6151_power(int on)
+{
+ if (on) {
+ trf6151_reg_write(REG_PWR, PWR_REGUL_ON | PWR_BANDGAP_ON);
+ /* wait until regulators are stable (25ms == 27100 qbits) */
+ tpu_enq_wait(5000);
+ tpu_enq_wait(5000);
+ tpu_enq_wait(5000);
+ tpu_enq_wait(5000);
+ tpu_enq_wait(5000);
+ tpu_enq_wait(2100);
+ } else
+ trf6151_reg_write(REG_PWR, PWR_BANDGAP_ON);
+}
+
+/* Set the operational mode of the TRF6151 chip */
+void trf6151_set_mode(enum trf6151_mode mode)
+{
+ uint16_t pwr = (PWR_REGUL_ON | PWR_BANDGAP_ON | (rf_band<<6));
+
+ switch (mode) {
+ case TRF6151_IDLE:
+ /* should we switch of the RF gain for power saving? */
+ break;
+ case TRF6151_RX:
+ pwr |= (PWR_SYNTHE_RX_ON | PWR_RX_MODE);
+ break;
+ case TRF6151_TX:
+#if 0
+ pwr |= (PWR_SYNTHE_TX_ON | PWR_TX_MODE);
+#else // Dieter: we should turn power control on (for TPU: check timing and order !)
+ pwr |= (PWR_SYNTHE_TX_ON | PWR_TX_MODE | PWR_PACTRL_APC | PWR_PACTRL_APCEN); // Dieter: TODO
+#endif
+ break;
+ }
+ trf6151_reg_write(REG_PWR, pwr);
+}
+
+static void trf6151_band_select(enum trf6151_gsm_band band)
+{
+ uint16_t pwr = trf6151_reg_cache[REG_PWR];
+
+ pwr &= ~(3 << 6);
+ pwr |= (band << 6);
+
+ trf6151_reg_write(REG_PWR, pwr);
+}
+
+/* Set ARFCN. Takes 2 reg_write, i.e. 8 TPU instructions */
+void trf6151_set_arfcn(uint16_t arfcn, int tx)
+{
+ uint32_t freq_khz;
+ uint16_t pll_config;
+ int uplink;
+ enum trf6151_gsm_band pll_band;
+
+ uplink = !!(arfcn & ARFCN_UPLINK);
+ arfcn != ~ARFCN_UPLINK;
+
+ switch (gsm_arfcn2band(arfcn)) {
+ case GSM_BAND_850:
+ case GSM_BAND_900:
+ case GSM_BAND_1800:
+ case GSM_BAND_1900:
+ /* Supported */
+ break;
+ case GSM_BAND_450:
+ case GSM_BAND_480:
+ case GSM_BAND_750:
+ case GSM_BAND_810:
+ printf("Unsupported band ! YMMV.\n");
+ break;
+ }
+
+ freq_khz = gsm_arfcn2freq10(arfcn, uplink) * 100;
+ printd("ARFCN %u -> %u kHz\n", arfcn, freq_khz);
+
+ if (!tx)
+ trf6151_pll_rx(freq_khz, &pll_config, &pll_band);
+ else
+ trf6151_pll_tx(freq_khz, &pll_config, &pll_band);
+
+ trf6151_band_select(pll_band);
+ trf6151_reg_write(REG_PLL, pll_config);
+
+ rf_band = pll_band;
+ rf_arfcn = arfcn; // TODO: arfcn is referenced at other places
+}
+
+void trf6151_calib_dc_offs(void)
+{
+ uint16_t rx = trf6151_reg_cache[REG_RX];
+
+ /* Set RX CAL Mode bit, it will re-set automatically */
+ trf6151_reg_write(REG_RX, rx | RX_CAL_MODE);
+ /* DC offset calibration can take up to 50us, i.e. 54.16 * 923ns*/
+ tpu_enq_wait(55);
+}
+
+uint8_t trf6151_get_gain_reg(void)
+{
+ uint16_t vga, reg_rx = trf6151_reg_cache[REG_RX];
+ uint8_t gain = 0;
+
+ switch ((reg_rx >> 9) & 3) {
+ case 0:
+ gain += TRF6151_FE_GAIN_LOW;
+ break;
+ case 3:
+ gain += TRF6151_FE_GAIN_HIGH;
+ break;
+ }
+
+ vga = (reg_rx >> RX_VGA_GAIN_SHIFT) & 0x1f;
+ if (vga < 6)
+ vga = 6;
+
+ gain += TRF6151_VGA_GAIN_MIN + (vga - 6) * 2;
+
+ return gain;
+}
+
+uint8_t trf6151_get_gain(void)
+{
+ uint8_t gain;
+
+ gain = trf6151_vga_dbm;
+ if (trf6151_gain_high)
+ gain += TRF6151_FE_GAIN_HIGH;
+ else
+ gain += TRF6151_FE_GAIN_LOW;
+
+ return gain;
+}
+
+void trf6151_test(uint16_t arfcn)
+{
+ /* Select ARFCN downlink */
+ trf6151_set_arfcn(arfcn, 0);
+
+ trf6151_set_mode(TRF6151_RX);
+ //trf6151_reg_write(REG_PWR, (PWR_SYNTHE_RX_ON | PWR_RX_MODE | PWR_REGUL_ON | (rf_band<<6) | PWR_BANDGAP_ON));
+ /* Wait for PLL stabilization (170us max) */
+ tpu_enq_wait(TRF6151_RX_PLL_DELAY);
+
+ /* Use DC offset calibration after RX mode has been switched on
+ * (might not be needed) */
+ trf6151_calib_dc_offs();
+
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+}
+
+void trf6151_tx_test(uint16_t arfcn)
+{
+ /* Select ARFCN uplink */
+ trf6151_set_arfcn(arfcn | ARFCN_UPLINK, 1);
+
+ trf6151_set_mode(TRF6151_TX);
+ tpu_enq_wait(TRF6151_RX_PLL_DELAY);
+
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+}
+
+#define TRF6151_REGWR_QBITS 8 /* 4 GSM qbits + 4 TPU instructions */
+#define TRF6151_RX_TPU_INSTR 4 /* set_gain_reg(1), set_arfcn(2), set_mode(1) */
+
+/* delay caused by this driver programming the TPU for RX mode */
+#define TRF6151_RX_TPU_DELAY (TRF6151_RX_TPU_INSTR * TRF6151_REGWR_QBITS)
+
+/* prepare a Rx window with the TRF6151 finished at time 'start' (in qbits) */
+void trf6151_rx_window(int16_t start_qbits, uint16_t arfcn)
+{
+ int16_t start_pll_qbits;
+
+ /* power up at the right time _before_ the 'start_qbits' point in time */
+ start_pll_qbits = add_mod5000(start_qbits, -(TRF6151_RX_PLL_DELAY + TRF6151_RX_TPU_DELAY));
+ tpu_enq_at(start_pll_qbits);
+
+ /* Set the AGC and PLL registers */
+ trf6151_set_arfcn(arfcn, 0);
+ trf6151_set_gain_reg(trf6151_vga_dbm, trf6151_gain_high);
+ trf6151_set_mode(TRF6151_RX);
+
+ /* FIXME: power down at the right time again */
+}
+
+/* prepare a Tx window with the TRF6151 finished at time 'start' (in qbits) */
+void trf6151_tx_window(int16_t start_qbits, uint16_t arfcn)
+{
+#ifdef CONFIG_TX_ENABLE
+ int16_t start_pll_qbits;
+
+ /* power up at the right time _before_ the 'start_qbits' point in time */
+ start_pll_qbits = add_mod5000(start_qbits, -(TRF6151_TX_PLL_DELAY + TRF6151_RX_TPU_DELAY));
+ tpu_enq_at(start_pll_qbits);
+
+ trf6151_set_arfcn(arfcn, 1);
+ trf6151_set_mode(TRF6151_TX);
+
+ /* FIXME: power down at the right time again */
+#endif
+}
+
+/* Given the expected input level of exp_inp dBm and the target of target_bb
+ * dBm, configure the RF Frontend with the respective gain */
+void trf6151_compute_gain(int16_t exp_inp, int16_t target_bb)
+{
+ /* TRF6151 VGA gain between 14 to 40 dB, plus 20db high/low */
+ int16_t exp_bb, delta;
+
+ /* calculate the dBm8 that we expect at the baseband */
+ exp_bb = exp_inp + system_inherent_gain;
+
+ /* calculate the error that we expect. */
+ delta = target_bb - exp_bb;
+
+ printd("computed gain %d\n", delta);
+ trf6151_set_gain(delta);
+}
+