From 9fcc469afa01fc9ea42e4cbb96c5b195c5bcd371 Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 11 Jan 2012 17:00:30 +0100 Subject: all reupped --- Src/osmolib/src/target/firmware/.gitignore | 9 + Src/osmolib/src/target/firmware/COPYING | 339 +++++ Src/osmolib/src/target/firmware/Makefile | 94 ++ Src/osmolib/src/target/firmware/Makefile.inc | 208 +++ Src/osmolib/src/target/firmware/Makefile.mtk | 32 + Src/osmolib/src/target/firmware/abb/twl3025.c | 363 +++++ .../src/target/firmware/apps/chainload/main.c | 53 + .../target/firmware/apps/compal_dsp_dump/main.c | 62 + .../src/target/firmware/apps/hello_world/main.c | 149 ++ Src/osmolib/src/target/firmware/apps/l1test/main.c | 249 ++++ Src/osmolib/src/target/firmware/apps/layer1/main.c | 135 ++ Src/osmolib/src/target/firmware/apps/loader/main.c | 444 ++++++ .../src/target/firmware/apps/loader/protocol.h | 37 + .../src/target/firmware/apps/loader_mtk/main.c | 366 +++++ .../src/target/firmware/apps/simtest/main.c | 307 ++++ .../src/target/firmware/board/common/calypso_pwl.S | 21 + .../target/firmware/board/common/calypso_uart.S | 92 ++ .../src/target/firmware/board/compal/LINKAGE.txt | 12 + .../firmware/board/compal/exceptions_redirect.S | 24 + .../firmware/board/compal/exceptions_redirected.S | 20 + .../src/target/firmware/board/compal/handlers.S | 79 + .../src/target/firmware/board/compal/header.S | 11 + .../src/target/firmware/board/compal/highram.lds | 121 ++ .../src/target/firmware/board/compal/macros.S | 76 + .../src/target/firmware/board/compal/ram.lds | 123 ++ .../src/target/firmware/board/compal/rf_power.c | 62 + .../target/firmware/board/compal/rffe_dualband.c | 102 ++ .../src/target/firmware/board/compal/start.ram.S | 26 + .../src/target/firmware/board/compal/start.rom.S | 32 + .../src/target/firmware/board/compal_e86/init.c | 143 ++ .../firmware/board/compal_e86/rffe_dualband_e86.c | 106 ++ .../target/firmware/board/compal_e88/LINKAGE.txt | 33 + .../firmware/board/compal_e88/MEMORY_MAP.txt | 21 + .../src/target/firmware/board/compal_e88/flash.lds | 134 ++ .../src/target/firmware/board/compal_e88/init.c | 136 ++ .../target/firmware/board/compal_e88/loader.lds | 147 ++ .../src/target/firmware/board/compal_e99/init.c | 140 ++ Src/osmolib/src/target/firmware/board/gta0x/init.c | 136 ++ .../src/target/firmware/board/gta0x/rf_power.c | 63 + .../firmware/board/gta0x/rffe_gta0x_triband.c | 131 ++ Src/osmolib/src/target/firmware/board/manifest.c | 7 + .../src/target/firmware/board/mediatek/macros.S | 76 + .../src/target/firmware/board/mediatek/ram.lds | 112 ++ .../src/target/firmware/board/mediatek/start.ram.S | 26 + .../src/target/firmware/board/mediatek/uart.c | 424 ++++++ .../src/target/firmware/board/mt62xx/init.c | 139 ++ .../src/target/firmware/board/pirelli_dpl10/init.c | 127 ++ .../target/firmware/board/pirelli_dpl10/rf_power.c | 63 + .../board/pirelli_dpl10/rffe_dpl10_triband.c | 136 ++ .../src/target/firmware/board/se_j100/init.c | 140 ++ Src/osmolib/src/target/firmware/calypso/Makefile | 4 + Src/osmolib/src/target/firmware/calypso/arm.c | 26 + .../src/target/firmware/calypso/backlight.c | 69 + Src/osmolib/src/target/firmware/calypso/buzzer.c | 86 ++ Src/osmolib/src/target/firmware/calypso/clock.c | 200 +++ Src/osmolib/src/target/firmware/calypso/dma.c | 44 + Src/osmolib/src/target/firmware/calypso/dsp.c | 693 +++++++++ .../src/target/firmware/calypso/dsp_bootcode.c | 9 + .../src/target/firmware/calypso/dsp_dumpcode.c | 45 + .../src/target/firmware/calypso/dsp_params.c | 94 ++ Src/osmolib/src/target/firmware/calypso/du.c | 51 + Src/osmolib/src/target/firmware/calypso/i2c.c | 123 ++ Src/osmolib/src/target/firmware/calypso/irq.c | 266 ++++ Src/osmolib/src/target/firmware/calypso/keypad.c | 198 +++ Src/osmolib/src/target/firmware/calypso/misc.c | 60 + Src/osmolib/src/target/firmware/calypso/rtc.c | 83 ++ Src/osmolib/src/target/firmware/calypso/sim.c | 740 ++++++++++ Src/osmolib/src/target/firmware/calypso/spi.c | 141 ++ Src/osmolib/src/target/firmware/calypso/timer.c | 156 ++ Src/osmolib/src/target/firmware/calypso/tpu.c | 346 +++++ Src/osmolib/src/target/firmware/calypso/tsp.c | 121 ++ Src/osmolib/src/target/firmware/calypso/uart.c | 440 ++++++ Src/osmolib/src/target/firmware/calypso/uwire.c | 136 ++ Src/osmolib/src/target/firmware/comm/Makefile | 5 + Src/osmolib/src/target/firmware/comm/msgb.c | 78 + Src/osmolib/src/target/firmware/comm/sercomm.c | 297 ++++ .../src/target/firmware/comm/sercomm_cons.c | 140 ++ Src/osmolib/src/target/firmware/comm/timer.c | 217 +++ Src/osmolib/src/target/firmware/display/display.c | 20 + .../src/target/firmware/display/font_r8x8.c | 261 ++++ .../src/target/firmware/display/font_r8x8_horiz.c | 261 ++++ Src/osmolib/src/target/firmware/display/ssd1783.c | 257 ++++ Src/osmolib/src/target/firmware/display/ssd1963.c | 210 +++ Src/osmolib/src/target/firmware/display/st7558.c | 121 ++ Src/osmolib/src/target/firmware/display/td014.c | 185 +++ Src/osmolib/src/target/firmware/flash/cfi_flash.c | 574 +++++++ .../src/target/firmware/include/abb/twl3025.h | 136 ++ Src/osmolib/src/target/firmware/include/arm.h | 7 + .../src/target/firmware/include/arpa/inet.h | 2 + .../src/target/firmware/include/asm/assembler.h | 113 ++ .../src/target/firmware/include/asm/atomic.h | 106 ++ .../src/target/firmware/include/asm/bitops.h | 225 +++ .../src/target/firmware/include/asm/div64.h | 48 + .../src/target/firmware/include/asm/linkage.h | 18 + .../src/target/firmware/include/asm/ptrace.h | 128 ++ Src/osmolib/src/target/firmware/include/asm/swab.h | 45 + .../src/target/firmware/include/asm/system.h | 123 ++ Src/osmolib/src/target/firmware/include/board.h | 8 + .../src/target/firmware/include/byteorder.h | 79 + .../target/firmware/include/calypso/backlight.h | 10 + .../src/target/firmware/include/calypso/buzzer.h | 34 + .../src/target/firmware/include/calypso/clock.h | 67 + .../src/target/firmware/include/calypso/dma.h | 6 + .../src/target/firmware/include/calypso/dsp.h | 41 + .../src/target/firmware/include/calypso/dsp_api.h | 1560 ++++++++++++++++++++ .../src/target/firmware/include/calypso/du.h | 32 + .../src/target/firmware/include/calypso/irq.h | 49 + .../firmware/include/calypso/l1_environment.h | 385 +++++ .../src/target/firmware/include/calypso/misc.h | 8 + .../src/target/firmware/include/calypso/rtc.h | 6 + .../src/target/firmware/include/calypso/sim.h | 191 +++ .../src/target/firmware/include/calypso/timer.h | 25 + .../src/target/firmware/include/calypso/tpu.h | 122 ++ .../src/target/firmware/include/calypso/tsp.h | 31 + .../src/target/firmware/include/comm/msgb.h | 161 ++ .../src/target/firmware/include/comm/sercomm.h | 57 + .../target/firmware/include/comm/sercomm_cons.h | 10 + .../src/target/firmware/include/comm/timer.h | 76 + Src/osmolib/src/target/firmware/include/console.h | 20 + Src/osmolib/src/target/firmware/include/ctors.h | 16 + Src/osmolib/src/target/firmware/include/ctype.h | 54 + Src/osmolib/src/target/firmware/include/debug.h | 31 + Src/osmolib/src/target/firmware/include/defines.h | 18 + Src/osmolib/src/target/firmware/include/delay.h | 7 + Src/osmolib/src/target/firmware/include/display.h | 49 + .../src/target/firmware/include/display/ssd1783.h | 56 + .../src/target/firmware/include/flash/cfi_flash.h | 41 + Src/osmolib/src/target/firmware/include/i2c.h | 7 + Src/osmolib/src/target/firmware/include/keypad.h | 66 + .../src/target/firmware/include/layer1/afc.h | 18 + .../src/target/firmware/include/layer1/agc.h | 7 + .../src/target/firmware/include/layer1/apc.h | 10 + .../src/target/firmware/include/layer1/async.h | 59 + .../src/target/firmware/include/layer1/avg.h | 23 + .../src/target/firmware/include/layer1/l23_api.h | 15 + .../target/firmware/include/layer1/mframe_sched.h | 67 + .../src/target/firmware/include/layer1/prim.h | 34 + .../src/target/firmware/include/layer1/rfch.h | 9 + .../target/firmware/include/layer1/sched_gsmtime.h | 24 + .../src/target/firmware/include/layer1/sync.h | 203 +++ .../target/firmware/include/layer1/tdma_sched.h | 73 + .../src/target/firmware/include/layer1/toa.h | 10 + .../target/firmware/include/layer1/tpu_window.h | 24 + Src/osmolib/src/target/firmware/include/manifest.h | 10 + Src/osmolib/src/target/firmware/include/memory.h | 28 + Src/osmolib/src/target/firmware/include/mtk/bfe.h | 107 ++ Src/osmolib/src/target/firmware/include/mtk/bpi.h | 20 + Src/osmolib/src/target/firmware/include/mtk/bsi.h | 41 + Src/osmolib/src/target/firmware/include/mtk/emi.h | 42 + .../src/target/firmware/include/mtk/mt6139.h | 60 + .../src/target/firmware/include/mtk/mt6235.h | 74 + .../firmware/include/mtk/mt6235_sciphone_g2.h | 38 + .../src/target/firmware/include/mtk/system.h | 195 +++ .../src/target/firmware/include/mtk/tdma_timer.h | 60 + .../src/target/firmware/include/rf/trf6151.h | 49 + Src/osmolib/src/target/firmware/include/rffe.h | 35 + Src/osmolib/src/target/firmware/include/spi.h | 7 + Src/osmolib/src/target/firmware/include/stdint.h | 36 + Src/osmolib/src/target/firmware/include/stdio.h | 52 + Src/osmolib/src/target/firmware/include/string.h | 12 + Src/osmolib/src/target/firmware/include/swab.h | 297 ++++ Src/osmolib/src/target/firmware/include/uart.h | 32 + Src/osmolib/src/target/firmware/include/uwire.h | 7 + Src/osmolib/src/target/firmware/layer1/Makefile | 9 + Src/osmolib/src/target/firmware/layer1/afc.c | 130 ++ Src/osmolib/src/target/firmware/layer1/agc.c | 62 + Src/osmolib/src/target/firmware/layer1/apc.c | 57 + Src/osmolib/src/target/firmware/layer1/async.c | 159 ++ Src/osmolib/src/target/firmware/layer1/avg.c | 57 + Src/osmolib/src/target/firmware/layer1/init.c | 73 + Src/osmolib/src/target/firmware/layer1/l23_api.c | 633 ++++++++ .../src/target/firmware/layer1/mframe_sched.c | 483 ++++++ Src/osmolib/src/target/firmware/layer1/prim_fbsb.c | 573 +++++++ Src/osmolib/src/target/firmware/layer1/prim_freq.c | 112 ++ Src/osmolib/src/target/firmware/layer1/prim_pm.c | 238 +++ Src/osmolib/src/target/firmware/layer1/prim_rach.c | 159 ++ .../src/target/firmware/layer1/prim_rx_nb.c | 215 +++ Src/osmolib/src/target/firmware/layer1/prim_tch.c | 752 ++++++++++ .../src/target/firmware/layer1/prim_tx_nb.c | 173 +++ .../src/target/firmware/layer1/prim_utils.c | 74 + Src/osmolib/src/target/firmware/layer1/rfch.c | 152 ++ .../src/target/firmware/layer1/sched_gsmtime.c | 119 ++ Src/osmolib/src/target/firmware/layer1/sync.c | 402 +++++ .../src/target/firmware/layer1/tdma_sched.c | 244 +++ Src/osmolib/src/target/firmware/layer1/toa.c | 80 + .../src/target/firmware/layer1/tpu_window.c | 174 +++ Src/osmolib/src/target/firmware/lib/Makefile | 7 + Src/osmolib/src/target/firmware/lib/bitops.h | 33 + Src/osmolib/src/target/firmware/lib/changebit.S | 21 + Src/osmolib/src/target/firmware/lib/clearbit.S | 22 + Src/osmolib/src/target/firmware/lib/console.c | 190 +++ .../src/target/firmware/lib/copy_template.S | 255 ++++ Src/osmolib/src/target/firmware/lib/ctors.c | 15 + Src/osmolib/src/target/firmware/lib/ctype.c | 34 + Src/osmolib/src/target/firmware/lib/delay.c | 16 + Src/osmolib/src/target/firmware/lib/div64.S | 200 +++ Src/osmolib/src/target/firmware/lib/lib1funcs.S | 334 +++++ Src/osmolib/src/target/firmware/lib/memcpy.S | 59 + Src/osmolib/src/target/firmware/lib/memset.S | 80 + Src/osmolib/src/target/firmware/lib/printf.c | 19 + Src/osmolib/src/target/firmware/lib/setbit.S | 22 + Src/osmolib/src/target/firmware/lib/string.c | 50 + .../src/target/firmware/lib/testchangebit.S | 18 + Src/osmolib/src/target/firmware/lib/testclearbit.S | 18 + Src/osmolib/src/target/firmware/lib/testsetbit.S | 18 + Src/osmolib/src/target/firmware/lib/vsprintf.c | 847 +++++++++++ Src/osmolib/src/target/firmware/rf/mt6139.c | 205 +++ Src/osmolib/src/target/firmware/rf/trf6151.c | 601 ++++++++ 208 files changed, 27091 insertions(+) create mode 100644 Src/osmolib/src/target/firmware/.gitignore create mode 100644 Src/osmolib/src/target/firmware/COPYING create mode 100644 Src/osmolib/src/target/firmware/Makefile create mode 100644 Src/osmolib/src/target/firmware/Makefile.inc create mode 100644 Src/osmolib/src/target/firmware/Makefile.mtk create mode 100644 Src/osmolib/src/target/firmware/abb/twl3025.c create mode 100644 Src/osmolib/src/target/firmware/apps/chainload/main.c create mode 100644 Src/osmolib/src/target/firmware/apps/compal_dsp_dump/main.c create mode 100644 Src/osmolib/src/target/firmware/apps/hello_world/main.c create mode 100644 Src/osmolib/src/target/firmware/apps/l1test/main.c create mode 100644 Src/osmolib/src/target/firmware/apps/layer1/main.c create mode 100644 Src/osmolib/src/target/firmware/apps/loader/main.c create mode 100644 Src/osmolib/src/target/firmware/apps/loader/protocol.h create mode 100644 Src/osmolib/src/target/firmware/apps/loader_mtk/main.c create mode 100644 Src/osmolib/src/target/firmware/apps/simtest/main.c create mode 100644 Src/osmolib/src/target/firmware/board/common/calypso_pwl.S create mode 100644 Src/osmolib/src/target/firmware/board/common/calypso_uart.S create mode 100644 Src/osmolib/src/target/firmware/board/compal/LINKAGE.txt create mode 100644 Src/osmolib/src/target/firmware/board/compal/exceptions_redirect.S create mode 100644 Src/osmolib/src/target/firmware/board/compal/exceptions_redirected.S create mode 100644 Src/osmolib/src/target/firmware/board/compal/handlers.S create mode 100644 Src/osmolib/src/target/firmware/board/compal/header.S create mode 100644 Src/osmolib/src/target/firmware/board/compal/highram.lds create mode 100644 Src/osmolib/src/target/firmware/board/compal/macros.S create mode 100644 Src/osmolib/src/target/firmware/board/compal/ram.lds create mode 100644 Src/osmolib/src/target/firmware/board/compal/rf_power.c create mode 100644 Src/osmolib/src/target/firmware/board/compal/rffe_dualband.c create mode 100644 Src/osmolib/src/target/firmware/board/compal/start.ram.S create mode 100644 Src/osmolib/src/target/firmware/board/compal/start.rom.S create mode 100644 Src/osmolib/src/target/firmware/board/compal_e86/init.c create mode 100644 Src/osmolib/src/target/firmware/board/compal_e86/rffe_dualband_e86.c create mode 100644 Src/osmolib/src/target/firmware/board/compal_e88/LINKAGE.txt create mode 100644 Src/osmolib/src/target/firmware/board/compal_e88/MEMORY_MAP.txt create mode 100644 Src/osmolib/src/target/firmware/board/compal_e88/flash.lds create mode 100644 Src/osmolib/src/target/firmware/board/compal_e88/init.c create mode 100644 Src/osmolib/src/target/firmware/board/compal_e88/loader.lds create mode 100644 Src/osmolib/src/target/firmware/board/compal_e99/init.c create mode 100644 Src/osmolib/src/target/firmware/board/gta0x/init.c create mode 100644 Src/osmolib/src/target/firmware/board/gta0x/rf_power.c create mode 100644 Src/osmolib/src/target/firmware/board/gta0x/rffe_gta0x_triband.c create mode 100644 Src/osmolib/src/target/firmware/board/manifest.c create mode 100644 Src/osmolib/src/target/firmware/board/mediatek/macros.S create mode 100644 Src/osmolib/src/target/firmware/board/mediatek/ram.lds create mode 100644 Src/osmolib/src/target/firmware/board/mediatek/start.ram.S create mode 100644 Src/osmolib/src/target/firmware/board/mediatek/uart.c create mode 100644 Src/osmolib/src/target/firmware/board/mt62xx/init.c create mode 100644 Src/osmolib/src/target/firmware/board/pirelli_dpl10/init.c create mode 100644 Src/osmolib/src/target/firmware/board/pirelli_dpl10/rf_power.c create mode 100644 Src/osmolib/src/target/firmware/board/pirelli_dpl10/rffe_dpl10_triband.c create mode 100644 Src/osmolib/src/target/firmware/board/se_j100/init.c create mode 100644 Src/osmolib/src/target/firmware/calypso/Makefile create mode 100644 Src/osmolib/src/target/firmware/calypso/arm.c create mode 100644 Src/osmolib/src/target/firmware/calypso/backlight.c create mode 100644 Src/osmolib/src/target/firmware/calypso/buzzer.c create mode 100644 Src/osmolib/src/target/firmware/calypso/clock.c create mode 100644 Src/osmolib/src/target/firmware/calypso/dma.c create mode 100644 Src/osmolib/src/target/firmware/calypso/dsp.c create mode 100644 Src/osmolib/src/target/firmware/calypso/dsp_bootcode.c create mode 100644 Src/osmolib/src/target/firmware/calypso/dsp_dumpcode.c create mode 100644 Src/osmolib/src/target/firmware/calypso/dsp_params.c create mode 100644 Src/osmolib/src/target/firmware/calypso/du.c create mode 100644 Src/osmolib/src/target/firmware/calypso/i2c.c create mode 100644 Src/osmolib/src/target/firmware/calypso/irq.c create mode 100644 Src/osmolib/src/target/firmware/calypso/keypad.c create mode 100644 Src/osmolib/src/target/firmware/calypso/misc.c create mode 100644 Src/osmolib/src/target/firmware/calypso/rtc.c create mode 100644 Src/osmolib/src/target/firmware/calypso/sim.c create mode 100644 Src/osmolib/src/target/firmware/calypso/spi.c create mode 100644 Src/osmolib/src/target/firmware/calypso/timer.c create mode 100644 Src/osmolib/src/target/firmware/calypso/tpu.c create mode 100644 Src/osmolib/src/target/firmware/calypso/tsp.c create mode 100644 Src/osmolib/src/target/firmware/calypso/uart.c create mode 100644 Src/osmolib/src/target/firmware/calypso/uwire.c create mode 100644 Src/osmolib/src/target/firmware/comm/Makefile create mode 100644 Src/osmolib/src/target/firmware/comm/msgb.c create mode 100644 Src/osmolib/src/target/firmware/comm/sercomm.c create mode 100644 Src/osmolib/src/target/firmware/comm/sercomm_cons.c create mode 100644 Src/osmolib/src/target/firmware/comm/timer.c create mode 100644 Src/osmolib/src/target/firmware/display/display.c create mode 100644 Src/osmolib/src/target/firmware/display/font_r8x8.c create mode 100644 Src/osmolib/src/target/firmware/display/font_r8x8_horiz.c create mode 100644 Src/osmolib/src/target/firmware/display/ssd1783.c create mode 100644 Src/osmolib/src/target/firmware/display/ssd1963.c create mode 100644 Src/osmolib/src/target/firmware/display/st7558.c create mode 100644 Src/osmolib/src/target/firmware/display/td014.c create mode 100644 Src/osmolib/src/target/firmware/flash/cfi_flash.c create mode 100644 Src/osmolib/src/target/firmware/include/abb/twl3025.h create mode 100644 Src/osmolib/src/target/firmware/include/arm.h create mode 100644 Src/osmolib/src/target/firmware/include/arpa/inet.h create mode 100644 Src/osmolib/src/target/firmware/include/asm/assembler.h create mode 100644 Src/osmolib/src/target/firmware/include/asm/atomic.h create mode 100644 Src/osmolib/src/target/firmware/include/asm/bitops.h create mode 100644 Src/osmolib/src/target/firmware/include/asm/div64.h create mode 100644 Src/osmolib/src/target/firmware/include/asm/linkage.h create mode 100644 Src/osmolib/src/target/firmware/include/asm/ptrace.h create mode 100644 Src/osmolib/src/target/firmware/include/asm/swab.h create mode 100644 Src/osmolib/src/target/firmware/include/asm/system.h create mode 100644 Src/osmolib/src/target/firmware/include/board.h create mode 100644 Src/osmolib/src/target/firmware/include/byteorder.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/backlight.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/buzzer.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/clock.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/dma.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/dsp.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/dsp_api.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/du.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/irq.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/l1_environment.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/misc.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/rtc.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/sim.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/timer.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/tpu.h create mode 100644 Src/osmolib/src/target/firmware/include/calypso/tsp.h create mode 100644 Src/osmolib/src/target/firmware/include/comm/msgb.h create mode 100644 Src/osmolib/src/target/firmware/include/comm/sercomm.h create mode 100644 Src/osmolib/src/target/firmware/include/comm/sercomm_cons.h create mode 100644 Src/osmolib/src/target/firmware/include/comm/timer.h create mode 100644 Src/osmolib/src/target/firmware/include/console.h create mode 100644 Src/osmolib/src/target/firmware/include/ctors.h create mode 100644 Src/osmolib/src/target/firmware/include/ctype.h create mode 100644 Src/osmolib/src/target/firmware/include/debug.h create mode 100644 Src/osmolib/src/target/firmware/include/defines.h create mode 100644 Src/osmolib/src/target/firmware/include/delay.h create mode 100644 Src/osmolib/src/target/firmware/include/display.h create mode 100644 Src/osmolib/src/target/firmware/include/display/ssd1783.h create mode 100644 Src/osmolib/src/target/firmware/include/flash/cfi_flash.h create mode 100644 Src/osmolib/src/target/firmware/include/i2c.h create mode 100644 Src/osmolib/src/target/firmware/include/keypad.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/afc.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/agc.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/apc.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/async.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/avg.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/l23_api.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/mframe_sched.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/prim.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/rfch.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/sched_gsmtime.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/sync.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/tdma_sched.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/toa.h create mode 100644 Src/osmolib/src/target/firmware/include/layer1/tpu_window.h create mode 100644 Src/osmolib/src/target/firmware/include/manifest.h create mode 100644 Src/osmolib/src/target/firmware/include/memory.h create mode 100644 Src/osmolib/src/target/firmware/include/mtk/bfe.h create mode 100644 Src/osmolib/src/target/firmware/include/mtk/bpi.h create mode 100644 Src/osmolib/src/target/firmware/include/mtk/bsi.h create mode 100644 Src/osmolib/src/target/firmware/include/mtk/emi.h create mode 100644 Src/osmolib/src/target/firmware/include/mtk/mt6139.h create mode 100644 Src/osmolib/src/target/firmware/include/mtk/mt6235.h create mode 100644 Src/osmolib/src/target/firmware/include/mtk/mt6235_sciphone_g2.h create mode 100644 Src/osmolib/src/target/firmware/include/mtk/system.h create mode 100644 Src/osmolib/src/target/firmware/include/mtk/tdma_timer.h create mode 100644 Src/osmolib/src/target/firmware/include/rf/trf6151.h create mode 100644 Src/osmolib/src/target/firmware/include/rffe.h create mode 100644 Src/osmolib/src/target/firmware/include/spi.h create mode 100644 Src/osmolib/src/target/firmware/include/stdint.h create mode 100644 Src/osmolib/src/target/firmware/include/stdio.h create mode 100644 Src/osmolib/src/target/firmware/include/string.h create mode 100644 Src/osmolib/src/target/firmware/include/swab.h create mode 100644 Src/osmolib/src/target/firmware/include/uart.h create mode 100644 Src/osmolib/src/target/firmware/include/uwire.h create mode 100644 Src/osmolib/src/target/firmware/layer1/Makefile create mode 100644 Src/osmolib/src/target/firmware/layer1/afc.c create mode 100644 Src/osmolib/src/target/firmware/layer1/agc.c create mode 100644 Src/osmolib/src/target/firmware/layer1/apc.c create mode 100644 Src/osmolib/src/target/firmware/layer1/async.c create mode 100644 Src/osmolib/src/target/firmware/layer1/avg.c create mode 100644 Src/osmolib/src/target/firmware/layer1/init.c create mode 100644 Src/osmolib/src/target/firmware/layer1/l23_api.c create mode 100644 Src/osmolib/src/target/firmware/layer1/mframe_sched.c create mode 100644 Src/osmolib/src/target/firmware/layer1/prim_fbsb.c create mode 100644 Src/osmolib/src/target/firmware/layer1/prim_freq.c create mode 100644 Src/osmolib/src/target/firmware/layer1/prim_pm.c create mode 100644 Src/osmolib/src/target/firmware/layer1/prim_rach.c create mode 100644 Src/osmolib/src/target/firmware/layer1/prim_rx_nb.c create mode 100644 Src/osmolib/src/target/firmware/layer1/prim_tch.c create mode 100644 Src/osmolib/src/target/firmware/layer1/prim_tx_nb.c create mode 100644 Src/osmolib/src/target/firmware/layer1/prim_utils.c create mode 100644 Src/osmolib/src/target/firmware/layer1/rfch.c create mode 100644 Src/osmolib/src/target/firmware/layer1/sched_gsmtime.c create mode 100644 Src/osmolib/src/target/firmware/layer1/sync.c create mode 100644 Src/osmolib/src/target/firmware/layer1/tdma_sched.c create mode 100644 Src/osmolib/src/target/firmware/layer1/toa.c create mode 100644 Src/osmolib/src/target/firmware/layer1/tpu_window.c create mode 100644 Src/osmolib/src/target/firmware/lib/Makefile create mode 100644 Src/osmolib/src/target/firmware/lib/bitops.h create mode 100644 Src/osmolib/src/target/firmware/lib/changebit.S create mode 100644 Src/osmolib/src/target/firmware/lib/clearbit.S create mode 100644 Src/osmolib/src/target/firmware/lib/console.c create mode 100644 Src/osmolib/src/target/firmware/lib/copy_template.S create mode 100644 Src/osmolib/src/target/firmware/lib/ctors.c create mode 100644 Src/osmolib/src/target/firmware/lib/ctype.c create mode 100644 Src/osmolib/src/target/firmware/lib/delay.c create mode 100644 Src/osmolib/src/target/firmware/lib/div64.S create mode 100644 Src/osmolib/src/target/firmware/lib/lib1funcs.S create mode 100644 Src/osmolib/src/target/firmware/lib/memcpy.S create mode 100644 Src/osmolib/src/target/firmware/lib/memset.S create mode 100644 Src/osmolib/src/target/firmware/lib/printf.c create mode 100644 Src/osmolib/src/target/firmware/lib/setbit.S create mode 100644 Src/osmolib/src/target/firmware/lib/string.c create mode 100644 Src/osmolib/src/target/firmware/lib/testchangebit.S create mode 100644 Src/osmolib/src/target/firmware/lib/testclearbit.S create mode 100644 Src/osmolib/src/target/firmware/lib/testsetbit.S create mode 100644 Src/osmolib/src/target/firmware/lib/vsprintf.c create mode 100644 Src/osmolib/src/target/firmware/rf/mt6139.c create mode 100644 Src/osmolib/src/target/firmware/rf/trf6151.c (limited to 'Src/osmolib/src/target/firmware') diff --git a/Src/osmolib/src/target/firmware/.gitignore b/Src/osmolib/src/target/firmware/.gitignore new file mode 100644 index 0000000..79e98df --- /dev/null +++ b/Src/osmolib/src/target/firmware/.gitignore @@ -0,0 +1,9 @@ +*.o +*.p +*.a +*.lst +*.bin +*.elf +*.map +*.size +*~ diff --git a/Src/osmolib/src/target/firmware/COPYING b/Src/osmolib/src/target/firmware/COPYING new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/Src/osmolib/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. + + + Copyright (C) + + 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. + + , 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/osmolib/src/target/firmware/Makefile b/Src/osmolib/src/target/firmware/Makefile new file mode 100644 index 0000000..4ccd395 --- /dev/null +++ b/Src/osmolib/src/target/firmware/Makefile @@ -0,0 +1,94 @@ + + +# 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 simtest chainload + + +# 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 +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 +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 +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 +compal_e86_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS) + +# Compal E99 + +compal_e99_OBJS=$(compal_COMMON_OBJS) board/compal_e99/init.o +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 +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 +DISPLAY_OBJS=display/font_r8x8.o display/font_r8x8_horiz.o display/st7558.o display/td014.o display/ssd1783.o display/ssd1963.o display/display.o +ABB_OBJS=abb/twl3025.o +RF_OBJS=rf/trf6151.o + +# Objects that go in all applications +ANY_APP_OBJS+=$(ABB_OBJS) $(RF_OBJS) $(DISPLAY_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/osmolib/src/target/firmware/Makefile.inc b/Src/osmolib/src/target/firmware/Makefile.inc new file mode 100644 index 0000000..1f54031 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/Makefile.mtk b/Src/osmolib/src/target/firmware/Makefile.mtk new file mode 100644 index 0000000..30fa2fc --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/abb/twl3025.c b/Src/osmolib/src/target/firmware/abb/twl3025.c new file mode 100644 index 0000000..564c34b --- /dev/null +++ b/Src/osmolib/src/target/firmware/abb/twl3025.c @@ -0,0 +1,363 @@ +/* Driver for Analog Baseband Circuit (TWL3025) */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 & 0x04) { + /* 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_power_off(); + } + 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) +{ + 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/osmolib/src/target/firmware/apps/chainload/main.c b/Src/osmolib/src/target/firmware/apps/chainload/main.c new file mode 100644 index 0000000..5121837 --- /dev/null +++ b/Src/osmolib/src/target/firmware/apps/chainload/main.c @@ -0,0 +1,53 @@ +/* Compal ramloader -> Calypso romloader Chainloading application */ + +/* (C) 2010 by Steve Markgraf + * + * 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 +#include +#include + +#include +#include +#include + +#include + +/* 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/osmolib/src/target/firmware/apps/compal_dsp_dump/main.c b/Src/osmolib/src/target/firmware/apps/compal_dsp_dump/main.c new file mode 100644 index 0000000..c823d0a --- /dev/null +++ b/Src/osmolib/src/target/firmware/apps/compal_dsp_dump/main.c @@ -0,0 +1,62 @@ +/* main program of Free Software for Calypso Phone */ + +/* (C) 2010 Harald Welte + * (C) 2010 Sylvain Munaut + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Main Program */ +const char *hr = "======================================================================\n"; + +int main(void) +{ + board_init(); + + puts("\n\nOSMOCOM Compal DSP Dumper (revision " GIT_REVISION ")\n"); + puts(hr); + + /* Dump device identification */ + dump_dev_id(); + puts(hr); + + /* Dump DSP content */ + dsp_dump(); + + while (1) { + update_timers(); + } +} + diff --git a/Src/osmolib/src/target/firmware/apps/hello_world/main.c b/Src/osmolib/src/target/firmware/apps/hello_world/main.c new file mode 100644 index 0000000..5e3ed85 --- /dev/null +++ b/Src/osmolib/src/target/firmware/apps/hello_world/main.c @@ -0,0 +1,149 @@ +/* main program of Free Software for Calypso Phone */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); + display_puts((char *) 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"); +} + +int main(void) +{ + board_init(); + + puts("\n\nOSMOCOM 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); + + /* Dump all memory */ + //dump_mem(); +#if 0 + /* Dump Bootloader */ + memdump_range((void *)0x00000000, 0x2000); + puts(hr); +#endif + + display_set_attr(DISP_ATTR_INVERT); + display_puts("Hello World"); + + sercomm_register_rx_cb(SC_DLCI_CONSOLE, console_rx_cb); + sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb); + + /* beyond this point we only react to interrupts */ + puts("entering interrupt loop\n"); + while (1) { + update_timers(); + } + + 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: + sprintf(test, "%d", code - KEY_0); + display_puts(test); + break; + case KEY_STAR: + sprintf(test, "*", 0); + display_puts(test); + break; + case KEY_HASH: + sprintf(test, "#", 0); + display_puts(test); + break; + default: + break; + } +} diff --git a/Src/osmolib/src/target/firmware/apps/l1test/main.c b/Src/osmolib/src/target/firmware/apps/l1test/main.c new file mode 100644 index 0000000..d1ca3d6 --- /dev/null +++ b/Src/osmolib/src/target/firmware/apps/l1test/main.c @@ -0,0 +1,249 @@ +/* main program of Free Software for Calypso Phone */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define SCAN + +#ifdef SCAN +/* if scanning is enabled, scan from 0 ... 124 */ +#define BASE_ARFCN 0 +#else +/* fixed ARFCN in GSM1800 at which Harald has his GSM test license */ +#define BASE_ARFCN 871 +#endif + +/* Main Program */ +const char *hr = "======================================================================\n"; + +/* Best ARFCN MAP ************************************************************/ + +struct arfcn_map { + uint16_t arfcn; + int16_t dbm8; +}; + +static struct arfcn_map best_arfcn_map[10]; +static void best_arfcn_update(uint16_t arfcn, int16_t dbm8) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE(best_arfcn_map); i++) { + if (best_arfcn_map[i].dbm8 < dbm8 || + best_arfcn_map[i].dbm8 == 0) { + best_arfcn_map[i].dbm8 = dbm8; + best_arfcn_map[i].arfcn = arfcn; + return; + } + } +} + +static void best_arfcn_dump(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(best_arfcn_map); i++) { + if (best_arfcn_map[i].dbm8 == 0) + continue; + printf("ARFCN %3d: %d dBm\n", + best_arfcn_map[i].arfcn, + best_arfcn_map[i].dbm8/8); + } +} + + +/* MAIN program **************************************************************/ + +enum l1test_state { + STATE_NONE, + STATE_PM, + STATE_FB, +}; + +static void l1test_state_change(enum l1test_state new_state) +{ + switch (new_state) { + case STATE_PM: + puts("Performing power measurement over GSM900\n"); + l1s_pm_test(1, BASE_ARFCN); + break; + case STATE_FB: + puts("Starting FCCH Recognition\n"); + l1s_fb_test(1, 0); + break; + case STATE_NONE: + /* disable frame interrupts */ + tpu_frame_irq_en(0, 0); + break; + } +} + +/* completion call-back for the L1 Sync Power Measurement */ +static void l1s_signal_cb(struct l1_signal *sig) +{ + uint16_t i, next_arfcn; + + switch (sig->signum) { + case L1_SIG_PM: + best_arfcn_update(sig->arfcn, sig->pm.dbm8[0]); + next_arfcn = sig->arfcn + 1; + + if (next_arfcn >= 124) { + puts("ARFCN Top 10 Rx Level\n"); + best_arfcn_dump(); + + trf6151_rx_window(0, best_arfcn_map[0].arfcn, 40, 0); + tpu_end_scenario(); + + /* PM phase completed, do FB det */ + l1test_state_change(STATE_FB); + + break; + } + + /* restart Power Measurement */ + l1s_pm_test(1, next_arfcn); + break; + case L1_SIG_NB: + puts("NB SNR "); + for (i = 0; i < 4; i++) { + uint16_t snr = sig->nb.meas[i].snr; + printf("%d.%03u ", l1s_snr_int(snr), l1s_snr_fract(snr)); + } + putchar('\n'); + printf("--> Frame %d %d 0x%04X ", sig->nb.fire, sig->nb.crc, sig->nb.num_biterr); + for (i = 0; i < ARRAY_SIZE(sig->nb.frame); i++) + printf("%02X ", sig->nb.frame[i]); + putchar('\n'); + break; + } +} + +static void key_handler(enum key_codes code, enum key_states state); + +int main(void) +{ + board_init(); + + puts("\n\nHello World from " __FILE__ " program code\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); + + display_set_attr(DISP_ATTR_INVERT); + display_puts("l1test.bin"); + + layer1_init(); + l1s_set_handler(&l1s_signal_cb); + + //dsp_checksum_task(); +#ifdef SCAN + l1test_state_change(STATE_PM); +#else + l1test_state_change(STATE_FB); +#endif + tpu_frame_irq_en(1, 1); + + while (1) { + update_timers(); + } + + /* 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; + } +} diff --git a/Src/osmolib/src/target/firmware/apps/layer1/main.c b/Src/osmolib/src/target/firmware/apps/layer1/main.c new file mode 100644 index 0000000..8eaf4a6 --- /dev/null +++ b/Src/osmolib/src/target/firmware/apps/layer1/main.c @@ -0,0 +1,135 @@ +/* main program of Free Software for Calypso Phone */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +const char *hr = "======================================================================\n"; + +/* MAIN program **************************************************************/ + +static void key_handler(enum key_codes code, enum key_states state); + +int main(void) +{ + board_init(); + + puts("\n\nOSMOCOM 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); + + display_puts("layer1.bin"); + + layer1_init(); + + display_unset_attr(DISP_ATTR_INVERT); + + tpu_frame_irq_en(1, 1); + + while (1) { + l1a_compl_execute(); + update_timers(); + } + + /* 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; + } +} + + diff --git a/Src/osmolib/src/target/firmware/apps/loader/main.c b/Src/osmolib/src/target/firmware/apps/loader/main.c new file mode 100644 index 0000000..2ff6f9c --- /dev/null +++ b/Src/osmolib/src/target/firmware/apps/loader/main.c @@ -0,0 +1,444 @@ +/* boot loader for Calypso phones */ + +/* (C) 2010 by Ingo Albrecht + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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\nOSMOCOM 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_get_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_get_u8(msg); + address = msgb_get_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_get_u8(msg); + crc = msgb_get_u16(msg); + address = msgb_get_u32(msg); + + data = msgb_get(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_get_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_get_u8(msg); + address = msgb_get_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_get_u8(msg); + address = msgb_get_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_get_u8(msg); + crc = msgb_get_u16(msg); + msgb_get_u8(msg); // XXX align + chip = msgb_get_u8(msg); + address = msgb_get_u32(msg); + + data = msgb_get(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/osmolib/src/target/firmware/apps/loader/protocol.h b/Src/osmolib/src/target/firmware/apps/loader/protocol.h new file mode 100644 index 0000000..0a61c89 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/apps/loader_mtk/main.c b/Src/osmolib/src/target/firmware/apps/loader_mtk/main.c new file mode 100644 index 0000000..9bfaa7e --- /dev/null +++ b/Src/osmolib/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 + * (C) 2011 by Wolfram Sang + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +#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\nOSMOCOM 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_get_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_get_u8(msg); + address = msgb_get_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_get_u8(msg); + crc = msgb_get_u16(msg); + address = msgb_get_u32(msg); + + data = msgb_get(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_get_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_get_u8(msg); + address = msgb_get_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_get_u8(msg); + address = msgb_get_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_get_u8(msg); + crc = msgb_get_u16(msg); + msgb_get_u8(msg); // XXX align + chip = msgb_get_u8(msg); + address = msgb_get_u32(msg); + + data = msgb_get(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/osmolib/src/target/firmware/apps/simtest/main.c b/Src/osmolib/src/target/firmware/apps/simtest/main.c new file mode 100644 index 0000000..83f708e --- /dev/null +++ b/Src/osmolib/src/target/firmware/apps/simtest/main.c @@ -0,0 +1,307 @@ +/* SIM test application */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DEBUG + +/* Dump bytes in hex on the console */ +static void myHexdump(uint8_t *data, int len) +{ + int i; + + for(i=0;i> 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]; +} + +/* 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(); + + /* 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 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); + + 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\nOSMOCOM 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 + + display_set_attr(DISP_ATTR_INVERT); + display_puts("SIM-TEST"); + + 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/osmolib/src/target/firmware/board/common/calypso_pwl.S b/Src/osmolib/src/target/firmware/board/common/calypso_pwl.S new file mode 100644 index 0000000..90e29bf --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/common/calypso_uart.S b/Src/osmolib/src/target/firmware/board/common/calypso_uart.S new file mode 100644 index 0000000..808cb05 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal/LINKAGE.txt b/Src/osmolib/src/target/firmware/board/compal/LINKAGE.txt new file mode 100644 index 0000000..1ae06fb --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal/exceptions_redirect.S b/Src/osmolib/src/target/firmware/board/compal/exceptions_redirect.S new file mode 100644 index 0000000..a216e60 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal/exceptions_redirected.S b/Src/osmolib/src/target/firmware/board/compal/exceptions_redirected.S new file mode 100644 index 0000000..6908396 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal/handlers.S b/Src/osmolib/src/target/firmware/board/compal/handlers.S new file mode 100644 index 0000000..ef044e3 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal/header.S b/Src/osmolib/src/target/firmware/board/compal/header.S new file mode 100644 index 0000000..747f680 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal/highram.lds b/Src/osmolib/src/target/firmware/board/compal/highram.lds new file mode 100644 index 0000000..1f0a5a6 --- /dev/null +++ b/Src/osmolib/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 = 0x00010000 + /* highram binary: our unitialized data, stacks, heap */ + IRAM (rw) : ORIGIN = 0x00830000, LENGTH = 0x00010000 +} +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/osmolib/src/target/firmware/board/compal/macros.S b/Src/osmolib/src/target/firmware/board/compal/macros.S new file mode 100644 index 0000000..613e6bd --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal/ram.lds b/Src/osmolib/src/target/firmware/board/compal/ram.lds new file mode 100644 index 0000000..342870d --- /dev/null +++ b/Src/osmolib/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 = 0x00010000 + /* compal-loaded binary: our unitialized data, stacks, heap */ + IRAM (rw) : ORIGIN = 0x00810000, LENGTH = 0x00010000 +} +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/osmolib/src/target/firmware/board/compal/rf_power.c b/Src/osmolib/src/target/firmware/board/compal/rf_power.c new file mode 100644 index 0000000..fbbe65a --- /dev/null +++ b/Src/osmolib/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 + * + * 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 +#include + +/* 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/osmolib/src/target/firmware/board/compal/rffe_dualband.c b/Src/osmolib/src/target/firmware/board/compal/rffe_dualband.c new file mode 100644 index 0000000..f4b7361 --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/compal/rffe_dualband.c @@ -0,0 +1,102 @@ +#include +#include + +#include +#include +#include +#include +#include + +/* 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/osmolib/src/target/firmware/board/compal/start.ram.S b/Src/osmolib/src/target/firmware/board/compal/start.ram.S new file mode 100644 index 0000000..c8f242c --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal/start.rom.S b/Src/osmolib/src/target/firmware/board/compal/start.rom.S new file mode 100644 index 0000000..211bea8 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal_e86/init.c b/Src/osmolib/src/target/firmware/board/compal_e86/init.c new file mode 100644 index 0000000..1de6193 --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/compal_e86/init.c @@ -0,0 +1,143 @@ +/* Initialization for the Compal E86 (Motorola C139/C140) */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by Steve Markgraf + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#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) */ + display = &td014_display; + display_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/osmolib/src/target/firmware/board/compal_e86/rffe_dualband_e86.c b/Src/osmolib/src/target/firmware/board/compal_e86/rffe_dualband_e86.c new file mode 100644 index 0000000..25bb099 --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/compal_e86/rffe_dualband_e86.c @@ -0,0 +1,106 @@ +#include +#include + +#include +#include +#include +#include +#include + +/* 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/osmolib/src/target/firmware/board/compal_e88/LINKAGE.txt b/Src/osmolib/src/target/firmware/board/compal_e88/LINKAGE.txt new file mode 100644 index 0000000..8adaf86 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal_e88/MEMORY_MAP.txt b/Src/osmolib/src/target/firmware/board/compal_e88/MEMORY_MAP.txt new file mode 100644 index 0000000..6094aa9 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal_e88/flash.lds b/Src/osmolib/src/target/firmware/board/compal_e88/flash.lds new file mode 100644 index 0000000..cf0f6a4 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal_e88/init.c b/Src/osmolib/src/target/firmware/board/compal_e88/init.c new file mode 100644 index 0000000..a5bf880 --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/compal_e88/init.c @@ -0,0 +1,136 @@ +/* Initialization for the Compal E88 (Motorola C115...C123) */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#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 */ + display = &st7558_display; + display_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/osmolib/src/target/firmware/board/compal_e88/loader.lds b/Src/osmolib/src/target/firmware/board/compal_e88/loader.lds new file mode 100644 index 0000000..a7a001f --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/compal_e99/init.c b/Src/osmolib/src/target/firmware/board/compal_e99/init.c new file mode 100644 index 0000000..0c218a8 --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/compal_e99/init.c @@ -0,0 +1,140 @@ +/* Initialization for the Compal E99 (Motorola C155) */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by Steve Markgraf + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#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 */ + display = &ssd1783_display; + display_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/osmolib/src/target/firmware/board/gta0x/init.c b/Src/osmolib/src/target/firmware/board/gta0x/init.c new file mode 100644 index 0000000..4f256ea --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/gta0x/init.c @@ -0,0 +1,136 @@ +/* Initialization for the Openmoko Freerunner modem */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#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 */ + display = &st7558_display; + display_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/osmolib/src/target/firmware/board/gta0x/rf_power.c b/Src/osmolib/src/target/firmware/board/gta0x/rf_power.c new file mode 100644 index 0000000..1c896f7 --- /dev/null +++ b/Src/osmolib/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 + * + * 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 +#include + +/* 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/osmolib/src/target/firmware/board/gta0x/rffe_gta0x_triband.c b/Src/osmolib/src/target/firmware/board/gta0x/rffe_gta0x_triband.c new file mode 100644 index 0000000..f118d29 --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/gta0x/rffe_gta0x_triband.c @@ -0,0 +1,131 @@ +#include +#include + +#include +#include +#include +#include +#include + +/* 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/osmolib/src/target/firmware/board/manifest.c b/Src/osmolib/src/target/firmware/board/manifest.c new file mode 100644 index 0000000..025a722 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/mediatek/macros.S b/Src/osmolib/src/target/firmware/board/mediatek/macros.S new file mode 100644 index 0000000..14ee6e6 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/mediatek/ram.lds b/Src/osmolib/src/target/firmware/board/mediatek/ram.lds new file mode 100644 index 0000000..a2af560 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/mediatek/start.ram.S b/Src/osmolib/src/target/firmware/board/mediatek/start.ram.S new file mode 100644 index 0000000..c8f242c --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/board/mediatek/uart.c b/Src/osmolib/src/target/firmware/board/mediatek/uart.c new file mode 100644 index 0000000..8e86b20 --- /dev/null +++ b/Src/osmolib/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 + * (C) 2010 by Ingo Albrecht + * (C) 2010 by Steve Markgraf + * (C) 2011 by Wolfram Sang + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +/* 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/osmolib/src/target/firmware/board/mt62xx/init.c b/Src/osmolib/src/target/firmware/board/mt62xx/init.c new file mode 100644 index 0000000..3f68375 --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/mt62xx/init.c @@ -0,0 +1,139 @@ +/* Initialization for the MT62xx Basebands */ + +/* (C) 2010 by Steve Markgraf + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +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/osmolib/src/target/firmware/board/pirelli_dpl10/init.c b/Src/osmolib/src/target/firmware/board/pirelli_dpl10/init.c new file mode 100644 index 0000000..53fb257 --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/pirelli_dpl10/init.c @@ -0,0 +1,127 @@ +/* Initialization for the Pirelli DP-L10 */ + +/* (C) 2010 by Harald Welte + * (C) 2011 by Steve Markgraf + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define ARMIO_LATCH_OUT 0xfffe4802 +#define ASIC_CONF_REG 0xfffef008 + +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); + writew(reg, ASIC_CONF_REG); +} + +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 */ + display = &st7558_display; + display_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/osmolib/src/target/firmware/board/pirelli_dpl10/rf_power.c b/Src/osmolib/src/target/firmware/board/pirelli_dpl10/rf_power.c new file mode 100644 index 0000000..9b89847 --- /dev/null +++ b/Src/osmolib/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 + * + * 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 +#include + +/* 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/osmolib/src/target/firmware/board/pirelli_dpl10/rffe_dpl10_triband.c b/Src/osmolib/src/target/firmware/board/pirelli_dpl10/rffe_dpl10_triband.c new file mode 100644 index 0000000..d4d1342 --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/pirelli_dpl10/rffe_dpl10_triband.c @@ -0,0 +1,136 @@ +#include +#include + +#include +#include +#include +#include +#include + +/* 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/osmolib/src/target/firmware/board/se_j100/init.c b/Src/osmolib/src/target/firmware/board/se_j100/init.c new file mode 100644 index 0000000..30c3e6b --- /dev/null +++ b/Src/osmolib/src/target/firmware/board/se_j100/init.c @@ -0,0 +1,140 @@ +/* Initialization for the Sony Ericsson J100 */ + +/* (C) 2010 by Harald Welte + * (C) 2010-11 by Steve Markgraf + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#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 */ + display = &ssd1963_display; + display_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/osmolib/src/target/firmware/calypso/Makefile b/Src/osmolib/src/target/firmware/calypso/Makefile new file mode 100644 index 0000000..610a82c --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/calypso/arm.c b/Src/osmolib/src/target/firmware/calypso/arm.c new file mode 100644 index 0000000..8794ee3 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/calypso/backlight.c b/Src/osmolib/src/target/firmware/calypso/backlight.c new file mode 100644 index 0000000..a18dcb9 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/backlight.c @@ -0,0 +1,69 @@ +/* Calypso DBB internal PWL (Pulse Width / Light) Driver */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#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/osmolib/src/target/firmware/calypso/buzzer.c b/Src/osmolib/src/target/firmware/calypso/buzzer.c new file mode 100644 index 0000000..e76906f --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/buzzer.c @@ -0,0 +1,86 @@ +/* Calypso DBB internal PWT (Pulse Width / T) Buzzer Driver */ + +/* (C) 2010 by Jose Pereira + * + * 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 +#include + +#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/osmolib/src/target/firmware/calypso/clock.c b/Src/osmolib/src/target/firmware/calypso/clock.c new file mode 100644 index 0000000..246b6e0 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/clock.c @@ -0,0 +1,200 @@ +/* Driver for Calypso clock management */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +//#define DEBUG +#include + +#include +#include + +#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/osmolib/src/target/firmware/calypso/dma.c b/Src/osmolib/src/target/firmware/calypso/dma.c new file mode 100644 index 0000000..35c5be8 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/dma.c @@ -0,0 +1,44 @@ +/* Driver for Calypso DMA controller */ + +/* (C) 2010 by Harald Welte + * + * 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 + +#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/osmolib/src/target/firmware/calypso/dsp.c b/Src/osmolib/src/target/firmware/calypso/dsp.c new file mode 100644 index 0000000..1daecb2 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/dsp.c @@ -0,0 +1,693 @@ +#define DEBUG +/* Driver for the Calypso integrated DSP */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +#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; isize; 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; isize; 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>= 1; + + if (be) { + for (i=0; i> 8; + *(mcu_buf++) = w; + } + if (odd) + *mcu_buf = *(dsp_buf++) >> 8; + } else { + for (i=0; i> 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<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<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<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/osmolib/src/target/firmware/calypso/dsp_bootcode.c b/Src/osmolib/src/target/firmware/calypso/dsp_bootcode.c new file mode 100644 index 0000000..2db4656 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/calypso/dsp_dumpcode.c b/Src/osmolib/src/target/firmware/calypso/dsp_dumpcode.c new file mode 100644 index 0000000..265a1c1 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/calypso/dsp_params.c b/Src/osmolib/src/target/firmware/calypso/dsp_params.c new file mode 100644 index 0000000..e08b46e --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/calypso/du.c b/Src/osmolib/src/target/firmware/calypso/du.c new file mode 100644 index 0000000..58783b0 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/du.c @@ -0,0 +1,51 @@ +/* Calypso DU (Debug Unit) Driver */ + +/* (C) 2010 by Ingo Albrecht + * + * 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 +#include +#include + +#include + +#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/osmolib/src/target/firmware/calypso/i2c.c b/Src/osmolib/src/target/firmware/calypso/i2c.c new file mode 100644 index 0000000..344424d --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/i2c.c @@ -0,0 +1,123 @@ +/* Driver for I2C Master Controller inside TI Calypso */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include + +#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 & 0x3f, 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", rerg & 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/osmolib/src/target/firmware/calypso/irq.c b/Src/osmolib/src/target/firmware/calypso/irq.c new file mode 100644 index 0000000..136fd55 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/irq.c @@ -0,0 +1,266 @@ +/* Driver for Calypso IRQ controller */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include + +#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/osmolib/src/target/firmware/calypso/keypad.c b/Src/osmolib/src/target/firmware/calypso/keypad.c new file mode 100644 index 0000000..fd4e0ff --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/keypad.c @@ -0,0 +1,198 @@ +/* Driver for the keypad attached to the TI Calypso */ + +/* (C) 2010 by roh + * + * 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 +#include + +#include +#include +#include +#include +#include + +#include +#include + + +#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 (state == RELEASED) + if (key == KEY_POWER) + twl3025_power_off(); + + if(key_handler) { + key_handler(key, state); + } +} + +volatile uint32_t lastbuttons = 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 == 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/osmolib/src/target/firmware/calypso/misc.c b/Src/osmolib/src/target/firmware/calypso/misc.c new file mode 100644 index 0000000..460cc5d --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/misc.c @@ -0,0 +1,60 @@ + +#include +#include +#include + +/* 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/osmolib/src/target/firmware/calypso/rtc.c b/Src/osmolib/src/target/firmware/calypso/rtc.c new file mode 100644 index 0000000..ce750c2 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/rtc.c @@ -0,0 +1,83 @@ +/* Driver for Calypso RTC controller */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include + +#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) +{ + if (tick_ctr & 1) + display_set_attr(DISP_ATTR_INVERT); + else + display_unset_attr(DISP_ATTR_INVERT); + 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/osmolib/src/target/firmware/calypso/sim.c b/Src/osmolib/src/target/firmware/calypso/sim.c new file mode 100644 index 0000000..a539cf8 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/sim.c @@ -0,0 +1,740 @@ +/* Driver for Simcard Controller inside TI Calypso/Iota */ + +/* (C) 2010 by Philipp Fabian Benedikt Maier + * + * 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 +#include + +#include +#include +#include +#include +#include + +static int sim_rx_character_count = 0; /* How many bytes have been received by calypso_sim_receive() */ +static int sim_tx_character_count = 0; /* How many bytes have been transmitted by calypso_sim_transmit() */ +static 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() */ +volatile static int rxDoneFlag = 0; /* Used for rx synchronization instead of a semaphore in calypso_sim_receive() */ +volatile static int txDoneFlag = 0; /* Used for rx synchronization instead of a semaphore in calypso_sim_transmit() */ + +/* Display Register dump */ +void calypso_sim_regdump(void) +{ +#if (SIM_DEBUG == 1) + unsigned int regVal; + + + 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; +} + +/* Apply power to the simcard (use nullpointer to ignore atr) */ +int calypso_sim_powerup(uint8_t *atr) +{ + /* Enable level shifters and voltage regulator */ + twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN | VRPCSIM_SIMSEL); +#if (SIM_DEBUG == 1) + puts(" * Power enabled!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + /* Enable clock */ + writew(REG_SIM_CMD_MODULE_CLK_EN | REG_SIM_CMD_CMDSTART, REG_SIM_CMD); +#if (SIM_DEBUG == 1) + puts(" * Clock enabled!\n"); +#endif + 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); +#if (SIM_DEBUG == 1) + puts(" * Reset released!\n"); +#endif + + /* Catch ATR */ + if(atr != 0) + return calypso_sim_receive(atr); + else + return 0; +} + + +/* Powerdown simcard */ +void calypso_sim_powerdown(void) +{ + writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFBYPASS, REG_SIM_CONF1); +#if (SIM_DEBUG == 1) + puts(" * Reset pulled down!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + writew(REG_SIM_CMD_MODULE_CLK_EN | REG_SIM_CMD_CMDSTOP, REG_SIM_CMD); +#if (SIM_DEBUG == 1) + puts(" * Clock disabled!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + writew(0, REG_SIM_CMD); +#if (SIM_DEBUG == 1) + puts(" * Module disabled!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + /* Disable level shifters and voltage regulator */ + twl3025_reg_write(VRPCSIM, 0); +#if (SIM_DEBUG == 1) + puts(" * Power disabled!\n"); +#endif + 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); +#if (SIM_DEBUG == 1) + puts(" * Reset pulled down!\n"); +#endif + + delay_ms(SIM_OPERATION_DELAY); + + /* Pull reset down */ + writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFSRSTLEV , REG_SIM_CONF1); +#if (SIM_DEBUG == 1) + puts(" * Reset released!\n"); +#endif + + /* Catch ATR */ + if(atr != 0) + return calypso_sim_receive(atr); + else + return 0; +} + +/* Receive raw data through the sim interface */ +int calypso_sim_receive(uint8_t *data) +{ + /* Prepare buffers and flags */ + rx_buffer = data; + sim_rx_character_count = 0; + rxDoneFlag = 0; + + /* 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); + + /* Wait till rxDoneFlag is set */ + while(rxDoneFlag == 0); + + /* Disable all interrupt driven functions by masking all interrupts */ + writew(0xFF, REG_SIM_MASKIT); + + /* Hand back the number of bytes received */ + return sim_rx_character_count; + + return; +} + +/* Transmit raw data through the sim interface */ +int calypso_sim_transmit(uint8_t *data, int length) +{ + /* 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++; + + /* Wait till rxDoneFlag is set */ + while(txDoneFlag == 0); + + /* Disable all interrupt driven functions by masking all interrupts */ + writew(0xFF, REG_SIM_MASKIT); + + return 0; +} + + +/* IRQ-Handler for simcard interface */ +void sim_irq_handler(enum irq_nr irq) +{ + int regVal = readw(REG_SIM_IT); + + + /* Display interrupt information */ +#if (SIM_DEBUG == 1) + puts("SIM-ISR: Interrupt caught: "); +#endif + if(regVal & REG_SIM_IT_SIM_NATR) + { +#if (SIM_DEBUG == 1) + puts(" No answer to reset!\n"); +#endif + } + + /* Used by: calypso_sim_receive() to determine when the transmission is over */ + if(regVal & REG_SIM_IT_SIM_WT) + { +#if (SIM_DEBUG == 1) + puts(" Character underflow!\n"); +#endif + rxDoneFlag = 1; + } + + if(regVal & REG_SIM_IT_SIM_OV) + { +#if (SIM_DEBUG == 1) + puts(" Receive overflow!\n"); +#endif + } + + /* Used by: calypso_sim_transmit() to transmit the data */ + if(regVal & REG_SIM_IT_SIM_TX) + { +#if (SIM_DEBUG == 1) + puts(" Waiting for character to transmit...\n"); +#endif + if(sim_tx_character_count >= sim_tx_character_length) + txDoneFlag = 1; + else + { + writew(*tx_buffer,REG_SIM_DTX); + tx_buffer++; + sim_tx_character_count++; + } + } + + /* Used by: calypso_sim_receive() to receive the incoming data */ + if(regVal & REG_SIM_IT_SIM_RX) + { +#if (SIM_DEBUG == 1) + puts(" Waiting characters to be read...\n"); +#endif + /* 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 = (uint8_t) (readw(REG_SIM_DRX) & 0xFF); + rx_buffer++; + } +} + +/* Transceive T0 Apdu to sim acording to GSM 11.11 Page 34 */ +int calypso_sim_transceive(uint8_t cla, /* Class (in GSM context mostly 0xA0 */ + uint8_t ins, /* Instruction */ + uint8_t p1, /* First parameter */ + uint8_t p2, /* Second parameter */ + uint8_t p3le, /* Length of the data that should be transceived */ + uint8_t *data, /* Data payload */ + uint8_t *status, /* Status word (2 byte array, see note 1) */ + uint8_t mode) /* Mode of operation: 1=GET, 0=PUT */ + + /* Note 1: You can use a null-pointer (0) if you are not interested in + the status word */ +{ + uint8_t transmissionBuffer[256]; + uint8_t numberOfReceivedBytes; + +#if (SIM_DEBUG == 1) + printf("SIM-T0: Transceiving APDU-Header: (%02x %02x %02x %02x %02x)\n",cla,ins,p1,p2,p3le); +#endif + + /* Transmit APDU header */ + memset(transmissionBuffer,0,sizeof(transmissionBuffer)); + transmissionBuffer[0] = cla; + transmissionBuffer[1] = ins; + transmissionBuffer[2] = p1; + transmissionBuffer[3] = p2; + transmissionBuffer[4] = p3le; + calypso_sim_transmit(transmissionBuffer,5); + + /* Case 1: No input, No Output */ + if(p3le == 0) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: Case 1: No input, No Output (See also GSM 11.11 Page 34)\n"); +#endif + numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer); + + if(numberOfReceivedBytes == 2) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received: %02x %02x\n", transmissionBuffer[0], transmissionBuffer[1]); +#endif + /* Hand back status word */ + if(status != 0) + { + status[0] = transmissionBuffer[0]; + status[1] = transmissionBuffer[1]; + } + + return 0; + } + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error -- aborting!\n"); +#endif + return -1; + } + } + + /* Case 2: No input / Output of known length */ + else if(mode == SIM_APDU_PUT) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: Case 2: No input / Output of known length (See also GSM 11.11 Page 34)\n"); +#endif + + numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer); + + /* Error situation: The card has aborted, sends no data but a status word */ + if(numberOfReceivedBytes == 2) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received (ERROR): %02x %02x\n", transmissionBuffer[0], transmissionBuffer[1]); +#endif + /* Hand back status word */ + if(status != 0) + { + status[0] = transmissionBuffer[0]; + status[1] = transmissionBuffer[1]; + } + + return 0; + } + /* Acknoledge byte received */ + else if(numberOfReceivedBytes == 1) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: ACK received: %02x\n", transmissionBuffer[0]); +#endif + /* Check if ACK is valid */ + if(transmissionBuffer[0] != ins) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Invalid ACK byte -- aborting!\n"); +#endif + return -1; + } + + /* Transmit body */ + calypso_sim_transmit(data,p3le); + + /* Receive status word */ + numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer); + + /* Check status word */ + if(numberOfReceivedBytes == 2) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received: %02x %02x\n", transmissionBuffer[0], transmissionBuffer[1]); +#endif + + /* Hand back status word */ + if(status != 0) + { + status[0] = transmissionBuffer[0]; + status[1] = transmissionBuffer[1]; + } + + return 0; + } + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Missing or invalid status word -- aborting!\n"); +#endif + return -1; + } + } + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Missing ACK byte -- aborting!\n"); +#endif + return -1; + } + } + + /* Case 4: Input / No output */ + else if(mode == SIM_APDU_GET) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: Case 4: Input / No output (See also GSM 11.11 Page 34)\n"); +#endif + + numberOfReceivedBytes = calypso_sim_receive(data); + + /* Error situation: The card has aborted, sends no data but a status word */ + if(numberOfReceivedBytes == 2) + { + +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received (ERROR): %02x %02x\n", data[0], data[1]); +#endif + /* Hand back status word */ + if(status != 0) + { + status[0] = data[0]; + status[1] = data[1]; + } + + return 0; + } + + /* Data correctly received */ + else if(numberOfReceivedBytes == p3le + 1 + 2) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: ACK received: %02x\n", data[0]); +#endif + /* Check if ACK is valid */ + if(data[0] != ins) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Invalid ACK byte -- aborting!\n"); +#endif + return -1; + } + +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received: %02x %02x\n", data[p3le + 1], data[p3le + 2]); +#endif + /* Hand back status word */ + if(status != 0) + { + status[0] = data[p3le + 1]; + status[1] = data[p3le + 2]; + } + + /* Move data one position left to cut away the ACK-Byte */ + memcpy(data,data+1,p3le); + + return 0; + } + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Incorrect or missing answer -- aborting!\n"); +#endif + return -1; + } + } + + /* Should not happen, if it happens then the programmer has submitted invalid parameters! */ + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Invalid case (program bug!) -- aborting!\n"); +#endif + } + + /* Note: The other cases are not implemented because they are already covered + by the CASE 1,2 and 4. */ + + return 0; +} + + +/* Initialize simcard interface */ +void calypso_sim_init(void) +{ + /* Register IRQ handler and turn interrupts on */ +#if (SIM_DEBUG == 1) + puts("SIM: Registering interrupt handler for simcard-interface\n"); +#endif + irq_register_handler(IRQ_SIMCARD, &sim_irq_handler); + irq_config(IRQ_SIMCARD, 0, 0, 0xff); + irq_enable(IRQ_SIMCARD); +} + diff --git a/Src/osmolib/src/target/firmware/calypso/spi.c b/Src/osmolib/src/target/firmware/calypso/spi.c new file mode 100644 index 0000000..049ac08 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/spi.c @@ -0,0 +1,141 @@ +/* Driver for SPI Master Controller inside TI Calypso */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +//#define DEBUG +#include + +#include +#include +#include + +#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/osmolib/src/target/firmware/calypso/timer.c b/Src/osmolib/src/target/firmware/calypso/timer.c new file mode 100644 index 0000000..1dd55f2 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/timer.c @@ -0,0 +1,156 @@ +/* Calypso DBB internal Timer Driver */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include + +#include + +#include +#include + +#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/osmolib/src/target/firmware/calypso/tpu.c b/Src/osmolib/src/target/firmware/calypso/tpu.c new file mode 100644 index 0000000..0b60292 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/tpu.c @@ -0,0 +1,346 @@ +/* Calypso DBB internal TPU (Time Processing Unit) Driver */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include + +/* 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 +#include +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/osmolib/src/target/firmware/calypso/tsp.c b/Src/osmolib/src/target/firmware/calypso/tsp.c new file mode 100644 index 0000000..5d24f48 --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/tsp.c @@ -0,0 +1,121 @@ +/* Calypso DBB internal TSP (Time Serial Port) Driver */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include + +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/osmolib/src/target/firmware/calypso/uart.c b/Src/osmolib/src/target/firmware/calypso/uart.c new file mode 100644 index 0000000..bcb56bd --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/uart.c @@ -0,0 +1,440 @@ +/* Calypso DBB internal UART Driver */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by Ingo Albrecht + * + * 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 + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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/osmolib/src/target/firmware/calypso/uwire.c b/Src/osmolib/src/target/firmware/calypso/uwire.c new file mode 100644 index 0000000..ac8f15e --- /dev/null +++ b/Src/osmolib/src/target/firmware/calypso/uwire.c @@ -0,0 +1,136 @@ +/* Driver for uWire Master Controller inside TI Calypso */ + +/* (C) 2010 by Sylvain Munaut + * + * 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 +#include + +//#define DEBUG +#include + +#include +#include +#include + +#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/osmolib/src/target/firmware/comm/Makefile b/Src/osmolib/src/target/firmware/comm/Makefile new file mode 100644 index 0000000..25fbb98 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/comm/msgb.c b/Src/osmolib/src/target/firmware/comm/msgb.c new file mode 100644 index 0000000..4215d24 --- /dev/null +++ b/Src/osmolib/src/target/firmware/comm/msgb.c @@ -0,0 +1,78 @@ +/* (C) 2008-2010 by Harald Welte + * 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 +#include +#include +#include +#include + +#include +#include + +#include + +#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/osmolib/src/target/firmware/comm/sercomm.c b/Src/osmolib/src/target/firmware/comm/sercomm.c new file mode 100644 index 0000000..ddc852c --- /dev/null +++ b/Src/osmolib/src/target/firmware/comm/sercomm.c @@ -0,0 +1,297 @@ +/* Serial communications layer, based on HDLC */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include + +#include + +#ifdef HOST_BUILD + +# define SERCOMM_RX_MSG_SIZE 2048 +# ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +# endif +# include + +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 +# include +# include + +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 +# include + +#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/osmolib/src/target/firmware/comm/sercomm_cons.c b/Src/osmolib/src/target/firmware/comm/sercomm_cons.c new file mode 100644 index 0000000..a0dca40 --- /dev/null +++ b/Src/osmolib/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 + * + * 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 +#include +#include + +#include + +#include + +#include +#include +#include +#include + +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/osmolib/src/target/firmware/comm/timer.c b/Src/osmolib/src/target/firmware/comm/timer.c new file mode 100644 index 0000000..6a649ae --- /dev/null +++ b/Src/osmolib/src/target/firmware/comm/timer.c @@ -0,0 +1,217 @@ +/* (C) 2008 by Holger Hans Peter Freyther + * (C) 2010 by Harald Welte + * 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 +#include +#include + +#include + +#include +#include + +#include + +static LLIST_HEAD(timer_list); + +unsigned long volatile jiffies; + +#define TIMER_HZ 100 + +#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 add_timer(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 update_timers */ + 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 schedule_timer(struct osmo_timer_list *timer, int milliseconds) +{ + timer->expires = jiffies + ((milliseconds * TIMER_HZ) / 1000); + add_timer(timer); +} + +void del_timer(struct osmo_timer_list *timer) +{ + if (timer->in_list) { + timer->active = 0; + timer->in_list = 0; + llist_del(&timer->entry); + } +} + +int 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(¤t_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 update_timers(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 + * del_timer, add_timer, schedule_timer 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 add_timer and del_timer 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) { + del_timer(timer); + } + } + + return work; +} + +int timer_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 (TIMER_HZ == 100) + hwtimer_load(2, 4062); + hwtimer_config(2, 0, 1); +#elif (TIMER_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/osmolib/src/target/firmware/display/display.c b/Src/osmolib/src/target/firmware/display/display.c new file mode 100644 index 0000000..1c8f1fb --- /dev/null +++ b/Src/osmolib/src/target/firmware/display/display.c @@ -0,0 +1,20 @@ + +#include + +#include + +struct display_driver *display; + +int display_puts(const char *str) +{ + char c; + + if (display->puts) + display->puts(str); + else { + while ((c = *str++)) + display_putchar(c); + } + + return 0; +} diff --git a/Src/osmolib/src/target/firmware/display/font_r8x8.c b/Src/osmolib/src/target/firmware/display/font_r8x8.c new file mode 100644 index 0000000..6f8315d --- /dev/null +++ b/Src/osmolib/src/target/firmware/display/font_r8x8.c @@ -0,0 +1,261 @@ +/* 8x8 font, vertical scanning */ + +const unsigned char fontdata_r8x8[] ={ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0x95, 0xb1, 0xb1, 0x95, 0x81, 0x7e, + 0x7e, 0xff, 0xeb, 0xcf, 0xcf, 0xeb, 0xff, 0x7e, + 0x0e, 0x1f, 0x3f, 0x7e, 0x3f, 0x1f, 0x0e, 0x00, + 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, + 0x00, 0x38, 0x38, 0x9f, 0xff, 0x9f, 0x38, 0x38, + 0x10, 0x38, 0xbc, 0xff, 0xbc, 0x38, 0x10, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, + 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, + 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, + 0x70, 0xf8, 0x88, 0x88, 0xfd, 0x7f, 0x07, 0x0f, + 0x00, 0x4e, 0x5f, 0xf1, 0xf1, 0x5f, 0x4e, 0x00, + 0xc0, 0xe0, 0xff, 0x7f, 0x05, 0x05, 0x07, 0x07, + 0xc0, 0xff, 0x7f, 0x05, 0x05, 0x65, 0x7f, 0x3f, + 0x5a, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x5a, + 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08, 0x00, + 0x08, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x00, + 0x00, 0x24, 0x66, 0xff, 0xff, 0x66, 0x24, 0x00, + 0x00, 0x5f, 0x5f, 0x00, 0x00, 0x5f, 0x5f, 0x00, + 0x06, 0x0f, 0x09, 0x7f, 0x7f, 0x01, 0x7f, 0x7f, + 0x40, 0xda, 0xbf, 0xa5, 0xfd, 0x59, 0x03, 0x02, + 0x00, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x00, + 0x80, 0x94, 0xb6, 0xff, 0xff, 0xb6, 0x94, 0x80, + 0x00, 0x04, 0x06, 0x7f, 0x7f, 0x06, 0x04, 0x00, + 0x00, 0x10, 0x30, 0x7f, 0x7f, 0x30, 0x10, 0x00, + 0x08, 0x08, 0x08, 0x2a, 0x3e, 0x1c, 0x08, 0x00, + 0x08, 0x1c, 0x3e, 0x2a, 0x08, 0x08, 0x08, 0x00, + 0x3c, 0x3c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, + 0x08, 0x1c, 0x3e, 0x08, 0x08, 0x3e, 0x1c, 0x08, + 0x30, 0x38, 0x3c, 0x3e, 0x3e, 0x3c, 0x38, 0x30, + 0x06, 0x0e, 0x1e, 0x3e, 0x3e, 0x1e, 0x0e, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x5f, 0x5f, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, 0x00, + 0x14, 0x7f, 0x7f, 0x14, 0x7f, 0x7f, 0x14, 0x00, + 0x00, 0x24, 0x2e, 0x6b, 0x6b, 0x3a, 0x12, 0x00, + 0x00, 0x46, 0x66, 0x30, 0x18, 0x0c, 0x66, 0x62, + 0x00, 0x30, 0x7a, 0x4f, 0x5d, 0x37, 0x7a, 0x48, + 0x00, 0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x3e, 0x63, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x41, 0x63, 0x3e, 0x1c, 0x00, 0x00, + 0x08, 0x2a, 0x3e, 0x1c, 0x1c, 0x3e, 0x2a, 0x08, + 0x08, 0x08, 0x3e, 0x3e, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xe0, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, + 0x00, 0x3e, 0x7f, 0x71, 0x59, 0x4d, 0x7f, 0x3e, + 0x00, 0x44, 0x42, 0x7f, 0x7f, 0x40, 0x40, 0x00, + 0x00, 0x62, 0x73, 0x59, 0x49, 0x6f, 0x66, 0x00, + 0x00, 0x22, 0x63, 0x49, 0x49, 0x7f, 0x36, 0x00, + 0x00, 0x18, 0x1c, 0x16, 0x53, 0x7f, 0x7f, 0x50, + 0x00, 0x27, 0x67, 0x45, 0x45, 0x7d, 0x39, 0x00, + 0x00, 0x3c, 0x7e, 0x4b, 0x49, 0x79, 0x30, 0x00, + 0x00, 0x03, 0x03, 0x71, 0x79, 0x0f, 0x07, 0x00, + 0x00, 0x36, 0x7f, 0x49, 0x49, 0x7f, 0x36, 0x00, + 0x00, 0x06, 0x4f, 0x49, 0x69, 0x3f, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xe6, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x1c, 0x36, 0x63, 0x41, 0x00, 0x00, + 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, + 0x00, 0x00, 0x41, 0x63, 0x36, 0x1c, 0x08, 0x00, + 0x00, 0x02, 0x03, 0x51, 0x59, 0x0f, 0x06, 0x00, + 0x00, 0x3e, 0x7f, 0x41, 0x5d, 0x55, 0x57, 0x1e, + 0x00, 0x7c, 0x7e, 0x13, 0x13, 0x7e, 0x7c, 0x00, + 0x00, 0x41, 0x7f, 0x7f, 0x49, 0x49, 0x7f, 0x36, + 0x00, 0x1c, 0x3e, 0x63, 0x41, 0x41, 0x63, 0x22, + 0x00, 0x41, 0x7f, 0x7f, 0x41, 0x63, 0x3e, 0x1c, + 0x00, 0x41, 0x7f, 0x7f, 0x49, 0x5d, 0x41, 0x63, + 0x00, 0x41, 0x7f, 0x7f, 0x49, 0x1d, 0x01, 0x03, + 0x00, 0x1c, 0x3e, 0x63, 0x41, 0x51, 0x73, 0x72, + 0x00, 0x7f, 0x7f, 0x08, 0x08, 0x7f, 0x7f, 0x00, + 0x00, 0x00, 0x41, 0x7f, 0x7f, 0x41, 0x00, 0x00, + 0x00, 0x30, 0x70, 0x40, 0x41, 0x7f, 0x3f, 0x01, + 0x00, 0x41, 0x7f, 0x7f, 0x08, 0x1c, 0x77, 0x63, + 0x00, 0x41, 0x7f, 0x7f, 0x41, 0x40, 0x60, 0x70, + 0x00, 0x7f, 0x7f, 0x0e, 0x1c, 0x0e, 0x7f, 0x7f, + 0x00, 0x7f, 0x7f, 0x06, 0x0c, 0x18, 0x7f, 0x7f, + 0x00, 0x3e, 0x7f, 0x41, 0x41, 0x41, 0x7f, 0x3e, + 0x00, 0x41, 0x7f, 0x7f, 0x49, 0x09, 0x0f, 0x06, + 0x00, 0x1e, 0x3f, 0x21, 0x71, 0x7f, 0x5e, 0x00, + 0x00, 0x41, 0x7f, 0x7f, 0x09, 0x19, 0x7f, 0x66, + 0x00, 0x22, 0x67, 0x4d, 0x59, 0x73, 0x22, 0x00, + 0x00, 0x03, 0x41, 0x7f, 0x7f, 0x41, 0x03, 0x00, + 0x00, 0x7f, 0x7f, 0x40, 0x40, 0x7f, 0x7f, 0x00, + 0x00, 0x1f, 0x3f, 0x60, 0x60, 0x3f, 0x1f, 0x00, + 0x00, 0x7f, 0x7f, 0x30, 0x18, 0x30, 0x7f, 0x7f, + 0x00, 0x43, 0x67, 0x3c, 0x18, 0x3c, 0x67, 0x43, + 0x00, 0x07, 0x4f, 0x78, 0x78, 0x4f, 0x07, 0x00, + 0x00, 0x47, 0x63, 0x71, 0x59, 0x4d, 0x67, 0x73, + 0x00, 0x00, 0x7f, 0x7f, 0x41, 0x41, 0x00, 0x00, + 0x00, 0x01, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, + 0x00, 0x00, 0x41, 0x41, 0x7f, 0x7f, 0x00, 0x00, + 0x00, 0x08, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x08, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, + 0x00, 0x20, 0x74, 0x54, 0x54, 0x3c, 0x78, 0x40, + 0x00, 0x41, 0x7f, 0x3f, 0x48, 0x48, 0x78, 0x30, + 0x00, 0x38, 0x7c, 0x44, 0x44, 0x6c, 0x28, 0x00, + 0x00, 0x30, 0x78, 0x48, 0x49, 0x3f, 0x7f, 0x40, + 0x00, 0x38, 0x7c, 0x54, 0x54, 0x5c, 0x18, 0x00, + 0x00, 0x48, 0x7e, 0x7f, 0x49, 0x03, 0x02, 0x00, + 0x00, 0x98, 0xbc, 0xa4, 0xa4, 0xf8, 0x7c, 0x04, + 0x00, 0x41, 0x7f, 0x7f, 0x08, 0x04, 0x7c, 0x78, + 0x00, 0x00, 0x44, 0x7d, 0x7d, 0x40, 0x00, 0x00, + 0x00, 0x60, 0xe0, 0x80, 0x80, 0xfd, 0x7d, 0x00, + 0x00, 0x41, 0x7f, 0x7f, 0x10, 0x38, 0x6c, 0x44, + 0x00, 0x00, 0x41, 0x7f, 0x7f, 0x40, 0x00, 0x00, + 0x00, 0x7c, 0x7c, 0x18, 0x38, 0x1c, 0x7c, 0x78, + 0x00, 0x7c, 0x7c, 0x04, 0x04, 0x7c, 0x78, 0x00, + 0x00, 0x38, 0x7c, 0x44, 0x44, 0x7c, 0x38, 0x00, + 0x00, 0x84, 0xfc, 0xf8, 0xa4, 0x24, 0x3c, 0x18, + 0x00, 0x18, 0x3c, 0x24, 0xa4, 0xf8, 0xfc, 0x84, + 0x00, 0x44, 0x7c, 0x78, 0x4c, 0x04, 0x1c, 0x18, + 0x00, 0x48, 0x5c, 0x54, 0x54, 0x74, 0x24, 0x00, + 0x00, 0x00, 0x04, 0x3e, 0x7f, 0x44, 0x24, 0x00, + 0x00, 0x3c, 0x7c, 0x40, 0x40, 0x3c, 0x7c, 0x40, + 0x00, 0x1c, 0x3c, 0x60, 0x60, 0x3c, 0x1c, 0x00, + 0x00, 0x3c, 0x7c, 0x70, 0x38, 0x70, 0x7c, 0x3c, + 0x00, 0x44, 0x6c, 0x38, 0x10, 0x38, 0x6c, 0x44, + 0x00, 0x9c, 0xbc, 0xa0, 0xa0, 0xfc, 0x7c, 0x00, + 0x00, 0x4c, 0x64, 0x74, 0x5c, 0x4c, 0x64, 0x00, + 0x00, 0x08, 0x08, 0x3e, 0x77, 0x41, 0x41, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x41, 0x77, 0x3e, 0x08, 0x08, 0x00, + 0x00, 0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, + 0x00, 0x70, 0x78, 0x4c, 0x46, 0x4c, 0x78, 0x70, + 0x00, 0x0e, 0x9f, 0x91, 0xb1, 0xfb, 0x4a, 0x00, + 0x00, 0x3a, 0x7a, 0x40, 0x40, 0x7a, 0x7a, 0x40, + 0x38, 0x7c, 0x54, 0x55, 0x5d, 0x19, 0x00, 0x00, + 0x02, 0x23, 0x75, 0x55, 0x55, 0x7d, 0x7b, 0x42, + 0x00, 0x21, 0x75, 0x54, 0x54, 0x7d, 0x79, 0x40, + 0x00, 0x21, 0x75, 0x55, 0x54, 0x7c, 0x78, 0x40, + 0x00, 0x20, 0x74, 0x57, 0x57, 0x7c, 0x78, 0x40, + 0x00, 0x18, 0x3c, 0xa4, 0xa4, 0xe4, 0x40, 0x00, + 0x02, 0x3b, 0x7d, 0x55, 0x55, 0x5d, 0x1b, 0x02, + 0x39, 0x7d, 0x54, 0x54, 0x5d, 0x19, 0x00, 0x00, + 0x00, 0x39, 0x7d, 0x55, 0x54, 0x5c, 0x18, 0x00, + 0x00, 0x01, 0x45, 0x7c, 0x7c, 0x41, 0x01, 0x00, + 0x00, 0x02, 0x03, 0x45, 0x7d, 0x7d, 0x43, 0x02, + 0x00, 0x01, 0x45, 0x7d, 0x7c, 0x40, 0x00, 0x00, + 0x00, 0x79, 0x7d, 0x16, 0x12, 0x16, 0x7d, 0x79, + 0x00, 0x70, 0x78, 0x2b, 0x2b, 0x78, 0x70, 0x00, + 0x44, 0x7c, 0x7c, 0x55, 0x55, 0x45, 0x00, 0x00, + 0x20, 0x74, 0x54, 0x54, 0x7c, 0x7c, 0x54, 0x54, + 0x00, 0x7c, 0x7e, 0x0b, 0x09, 0x7f, 0x7f, 0x49, + 0x00, 0x32, 0x7b, 0x49, 0x49, 0x7b, 0x32, 0x00, + 0x00, 0x32, 0x7a, 0x48, 0x48, 0x7a, 0x32, 0x00, + 0x00, 0x32, 0x7a, 0x4a, 0x48, 0x78, 0x30, 0x00, + 0x00, 0x3a, 0x7b, 0x41, 0x41, 0x7b, 0x7a, 0x40, + 0x00, 0x3a, 0x7a, 0x42, 0x40, 0x78, 0x78, 0x40, + 0x9a, 0xba, 0xa0, 0xa0, 0xfa, 0x7a, 0x00, 0x00, + 0x01, 0x19, 0x3c, 0x66, 0x66, 0x3c, 0x19, 0x01, + 0x00, 0x3d, 0x7d, 0x40, 0x40, 0x7d, 0x3d, 0x00, + 0x00, 0x18, 0x3c, 0x24, 0xe7, 0xe7, 0x24, 0x24, + 0x00, 0x68, 0x7e, 0x7f, 0x49, 0x43, 0x66, 0x20, + 0x00, 0x2b, 0x2f, 0xfc, 0xfc, 0x2f, 0x2b, 0x00, + 0xff, 0xff, 0x09, 0x09, 0x2f, 0xf6, 0xf8, 0xa0, + 0x40, 0xc0, 0x88, 0xfe, 0x7f, 0x09, 0x03, 0x02, + 0x00, 0x20, 0x74, 0x54, 0x55, 0x7d, 0x79, 0x40, + 0x00, 0x00, 0x44, 0x7d, 0x7d, 0x41, 0x00, 0x00, + 0x00, 0x30, 0x78, 0x48, 0x4a, 0x7a, 0x32, 0x00, + 0x00, 0x38, 0x78, 0x40, 0x42, 0x7a, 0x7a, 0x40, + 0x00, 0x7a, 0x7a, 0x0a, 0x0a, 0x7a, 0x70, 0x00, + 0x00, 0x7d, 0x7d, 0x19, 0x31, 0x7d, 0x7d, 0x00, + 0x00, 0x00, 0x26, 0x2f, 0x29, 0x2f, 0x2f, 0x28, + 0x00, 0x00, 0x26, 0x2f, 0x29, 0x2f, 0x26, 0x00, + 0x00, 0x30, 0x78, 0x4d, 0x45, 0x60, 0x20, 0x00, + 0x00, 0x38, 0x38, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x38, 0x38, 0x00, 0x00, + 0x4f, 0x6f, 0x30, 0x18, 0xcc, 0xee, 0xbb, 0x91, + 0x4f, 0x6f, 0x30, 0x18, 0x6c, 0x76, 0xfb, 0xf9, + 0x00, 0x00, 0x00, 0x7b, 0x7b, 0x00, 0x00, 0x00, + 0x08, 0x1c, 0x36, 0x22, 0x08, 0x1c, 0x36, 0x22, + 0x22, 0x36, 0x1c, 0x08, 0x22, 0x36, 0x1c, 0x08, + 0xaa, 0x00, 0x55, 0x00, 0xaa, 0x00, 0x55, 0x00, + 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, + 0xdd, 0xff, 0xaa, 0x77, 0xdd, 0xaa, 0xff, 0x77, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x14, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x10, 0x10, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0x10, 0x10, 0xf0, 0xf0, 0x10, 0xf0, 0xf0, 0x00, + 0x14, 0x14, 0x14, 0xfc, 0xfc, 0x00, 0x00, 0x00, + 0x14, 0x14, 0xf7, 0xf7, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, + 0x14, 0x14, 0xf4, 0xf4, 0x04, 0xfc, 0xfc, 0x00, + 0x14, 0x14, 0x17, 0x17, 0x10, 0x1f, 0x1f, 0x00, + 0x10, 0x10, 0x1f, 0x1f, 0x10, 0x1f, 0x1f, 0x00, + 0x14, 0x14, 0x14, 0x1f, 0x1f, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0xf0, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x1f, 0x1f, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xf0, 0xf0, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xff, 0xff, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x14, 0x14, 0x14, + 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x10, + 0x00, 0x00, 0x1f, 0x1f, 0x10, 0x17, 0x17, 0x14, + 0x00, 0x00, 0xfc, 0xfc, 0x04, 0xf4, 0xf4, 0x14, + 0x14, 0x14, 0x17, 0x17, 0x10, 0x17, 0x17, 0x14, + 0x14, 0x14, 0xf4, 0xf4, 0x04, 0xf4, 0xf4, 0x14, + 0x00, 0x00, 0xff, 0xff, 0x00, 0xf7, 0xf7, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xf7, 0xf7, 0x00, 0xf7, 0xf7, 0x14, + 0x14, 0x14, 0x14, 0x17, 0x17, 0x14, 0x14, 0x14, + 0x10, 0x10, 0x1f, 0x1f, 0x10, 0x1f, 0x1f, 0x10, + 0x14, 0x14, 0x14, 0xf4, 0xf4, 0x14, 0x14, 0x14, + 0x10, 0x10, 0xf0, 0xf0, 0x10, 0xf0, 0xf0, 0x10, + 0x00, 0x00, 0x1f, 0x1f, 0x10, 0x1f, 0x1f, 0x10, + 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x14, 0x14, 0x14, + 0x00, 0x00, 0x00, 0xfc, 0xfc, 0x14, 0x14, 0x14, + 0x00, 0x00, 0xf0, 0xf0, 0x10, 0xf0, 0xf0, 0x10, + 0x10, 0x10, 0xff, 0xff, 0x10, 0xff, 0xff, 0x10, + 0x14, 0x14, 0x14, 0xff, 0xff, 0x14, 0x14, 0x14, + 0x10, 0x10, 0x10, 0x1f, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xf0, 0x10, 0x10, 0x10, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x00, 0x38, 0x7c, 0x44, 0x6c, 0x38, 0x6c, 0x44, + 0x00, 0xfc, 0xfe, 0x2a, 0x2a, 0x3e, 0x14, 0x00, + 0x00, 0x7e, 0x7e, 0x02, 0x02, 0x06, 0x06, 0x00, + 0x00, 0x02, 0x7e, 0x7e, 0x02, 0x7e, 0x7e, 0x02, + 0x00, 0x63, 0x77, 0x5d, 0x49, 0x63, 0x63, 0x00, + 0x00, 0x38, 0x7c, 0x44, 0x7c, 0x3c, 0x04, 0x04, + 0x00, 0x80, 0xfe, 0x7e, 0x20, 0x20, 0x3e, 0x1e, + 0x00, 0x04, 0x06, 0x02, 0x7e, 0x7c, 0x06, 0x02, + 0x00, 0x99, 0xbd, 0xe7, 0xe7, 0xbd, 0x99, 0x00, + 0x00, 0x1c, 0x3e, 0x6b, 0x49, 0x6b, 0x3e, 0x1c, + 0x00, 0x4c, 0x7e, 0x73, 0x01, 0x73, 0x7e, 0x4c, + 0x00, 0x30, 0x78, 0x4a, 0x4f, 0x7d, 0x39, 0x00, + 0x18, 0x3c, 0x24, 0x3c, 0x3c, 0x24, 0x3c, 0x18, + 0x98, 0xfc, 0x64, 0x3c, 0x3e, 0x27, 0x3d, 0x18, + 0x00, 0x1c, 0x3e, 0x6b, 0x49, 0x49, 0x00, 0x00, + 0x00, 0x7e, 0x7f, 0x01, 0x01, 0x7f, 0x7e, 0x00, + 0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x00, + 0x00, 0x44, 0x44, 0x5f, 0x5f, 0x44, 0x44, 0x00, + 0x00, 0x40, 0x51, 0x5b, 0x4e, 0x44, 0x40, 0x00, + 0x00, 0x40, 0x44, 0x4e, 0x5b, 0x51, 0x40, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x07, 0x06, + 0x60, 0xe0, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x6b, 0x6b, 0x08, 0x08, 0x00, + 0x00, 0x24, 0x36, 0x12, 0x36, 0x24, 0x36, 0x12, + 0x00, 0x00, 0x06, 0x0f, 0x09, 0x0f, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x30, 0x70, 0xc0, 0xff, 0xff, 0x01, 0x01, + 0x00, 0x1f, 0x1f, 0x01, 0x1f, 0x1e, 0x00, 0x00, + 0x00, 0x19, 0x1d, 0x17, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + diff --git a/Src/osmolib/src/target/firmware/display/font_r8x8_horiz.c b/Src/osmolib/src/target/firmware/display/font_r8x8_horiz.c new file mode 100644 index 0000000..046d09b --- /dev/null +++ b/Src/osmolib/src/target/firmware/display/font_r8x8_horiz.c @@ -0,0 +1,261 @@ +/* 8x8 font, right aligned, horizontal scanning */ + +const unsigned char fontdata_r8x8_horiz[] ={ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7e,0x81,0xa5,0x81,0xbd,0x99,0x81,0x7e, + 0x7e,0xff,0xdb,0xff,0xc3,0xe7,0xff,0x7e, + 0x6c,0xfe,0xfe,0xfe,0x7c,0x38,0x10,0x00, + 0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x08,0x00, + 0x1c,0x1c,0x1c,0x7f,0x7f,0x6b,0x08,0x1c, + 0x10,0x10,0x38,0x7c,0xfe,0x7c,0x10,0x38, + 0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00, + 0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff, + 0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00, + 0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff, + 0x0f,0x07,0x0f,0x7d,0xcc,0xcc,0xcc,0x78, + 0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18, + 0x3f,0x33,0x3f,0x30,0x30,0x70,0xf0,0xe0, + 0x7f,0x63,0x7f,0x63,0x63,0x67,0xe6,0xc0, + 0x18,0xdb,0x3c,0xe7,0xe7,0x3c,0xdb,0x18, + 0x80,0xe0,0xf8,0xfe,0xf8,0xe0,0x80,0x00, + 0x02,0x0e,0x3e,0xfe,0x3e,0x0e,0x02,0x00, + 0x18,0x3c,0x7e,0x18,0x18,0x7e,0x3c,0x18, + 0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00, + 0x7f,0xdb,0xdb,0x7b,0x1b,0x1b,0x1b,0x00, + 0x3e,0x63,0x38,0x6c,0x6c,0x38,0xcc,0x78, + 0x00,0x00,0x00,0x00,0x7e,0x7e,0x7e,0x00, + 0x18,0x3c,0x7e,0x18,0x7e,0x3c,0x18,0xff, + 0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x00, + 0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00, + 0x00,0x18,0x0c,0xfe,0x0c,0x18,0x00,0x00, + 0x00,0x30,0x60,0xfe,0x60,0x30,0x00,0x00, + 0x00,0x00,0xc0,0xc0,0xc0,0xfe,0x00,0x00, + 0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00, + 0x00,0x18,0x3c,0x7e,0xff,0xff,0x00,0x00, + 0x00,0xff,0xff,0x7e,0x3c,0x18,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00, + 0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x00, + 0x6c,0x6c,0xfe,0x6c,0xfe,0x6c,0x6c,0x00, + 0x18,0x3e,0x60,0x3c,0x06,0x7c,0x18,0x00, + 0x00,0x63,0x66,0x0c,0x18,0x33,0x63,0x00, + 0x1c,0x36,0x1c,0x3b,0x6e,0x66,0x3b,0x00, + 0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00, + 0x0c,0x18,0x30,0x30,0x30,0x18,0x0c,0x00, + 0x30,0x18,0x0c,0x0c,0x0c,0x18,0x30,0x00, + 0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00, + 0x00,0x30,0x30,0xfc,0x30,0x30,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30, + 0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00, + 0x03,0x06,0x0c,0x18,0x30,0x60,0x40,0x00, + 0x3e,0x63,0x67,0x6f,0x7b,0x73,0x3e,0x00, + 0x18,0x38,0x58,0x18,0x18,0x18,0x7e,0x00, + 0x3c,0x66,0x06,0x1c,0x30,0x66,0x7e,0x00, + 0x3c,0x66,0x06,0x1c,0x06,0x66,0x3c,0x00, + 0x0e,0x1e,0x36,0x66,0x7f,0x06,0x0f,0x00, + 0x7e,0x60,0x7c,0x06,0x06,0x66,0x3c,0x00, + 0x1c,0x30,0x60,0x7c,0x66,0x66,0x3c,0x00, + 0x7e,0x66,0x06,0x0c,0x18,0x18,0x18,0x00, + 0x3c,0x66,0x66,0x3c,0x66,0x66,0x3c,0x00, + 0x3c,0x66,0x66,0x3e,0x06,0x0c,0x38,0x00, + 0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00, + 0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30, + 0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x00, + 0x00,0x00,0x7e,0x00,0x00,0x7e,0x00,0x00, + 0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x00, + 0x3c,0x66,0x06,0x0c,0x18,0x00,0x18,0x00, + 0x3e,0x63,0x6f,0x69,0x6f,0x60,0x3e,0x00, + 0x18,0x3c,0x66,0x66,0x7e,0x66,0x66,0x00, + 0x7e,0x33,0x33,0x3e,0x33,0x33,0x7e,0x00, + 0x1e,0x33,0x60,0x60,0x60,0x33,0x1e,0x00, + 0x7c,0x36,0x33,0x33,0x33,0x36,0x7c,0x00, + 0x7f,0x31,0x34,0x3c,0x34,0x31,0x7f,0x00, + 0x7f,0x31,0x34,0x3c,0x34,0x30,0x78,0x00, + 0x1e,0x33,0x60,0x60,0x67,0x33,0x1f,0x00, + 0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00, + 0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00, + 0x0f,0x06,0x06,0x06,0x66,0x66,0x3c,0x00, + 0x73,0x33,0x36,0x3c,0x36,0x33,0x73,0x00, + 0x78,0x30,0x30,0x30,0x31,0x33,0x7f,0x00, + 0x63,0x77,0x7f,0x7f,0x6b,0x63,0x63,0x00, + 0x63,0x73,0x7b,0x6f,0x67,0x63,0x63,0x00, + 0x3e,0x63,0x63,0x63,0x63,0x63,0x3e,0x00, + 0x7e,0x33,0x33,0x3e,0x30,0x30,0x78,0x00, + 0x3c,0x66,0x66,0x66,0x6e,0x3c,0x0e,0x00, + 0x7e,0x33,0x33,0x3e,0x36,0x33,0x73,0x00, + 0x3c,0x66,0x30,0x18,0x0c,0x66,0x3c,0x00, + 0x7e,0x5a,0x18,0x18,0x18,0x18,0x3c,0x00, + 0x66,0x66,0x66,0x66,0x66,0x66,0x7e,0x00, + 0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00, + 0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00, + 0x63,0x63,0x36,0x1c,0x1c,0x36,0x63,0x00, + 0x66,0x66,0x66,0x3c,0x18,0x18,0x3c,0x00, + 0x7f,0x63,0x46,0x0c,0x19,0x33,0x7f,0x00, + 0x3c,0x30,0x30,0x30,0x30,0x30,0x3c,0x00, + 0x60,0x30,0x18,0x0c,0x06,0x03,0x01,0x00, + 0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00, + 0x08,0x1c,0x36,0x63,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, + 0x18,0x18,0x0c,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x3c,0x06,0x3e,0x66,0x3b,0x00, + 0x70,0x30,0x30,0x3e,0x33,0x33,0x6e,0x00, + 0x00,0x00,0x3c,0x66,0x60,0x66,0x3c,0x00, + 0x0e,0x06,0x06,0x3e,0x66,0x66,0x3b,0x00, + 0x00,0x00,0x3c,0x66,0x7e,0x60,0x3c,0x00, + 0x1c,0x36,0x30,0x78,0x30,0x30,0x78,0x00, + 0x00,0x00,0x3b,0x66,0x66,0x3e,0x06,0x7c, + 0x70,0x30,0x36,0x3b,0x33,0x33,0x73,0x00, + 0x18,0x00,0x38,0x18,0x18,0x18,0x3c,0x00, + 0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3c, + 0x70,0x30,0x33,0x36,0x3c,0x36,0x73,0x00, + 0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00, + 0x00,0x00,0x66,0x7f,0x7f,0x6b,0x63,0x00, + 0x00,0x00,0x7c,0x66,0x66,0x66,0x66,0x00, + 0x00,0x00,0x3c,0x66,0x66,0x66,0x3c,0x00, + 0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x78, + 0x00,0x00,0x3b,0x66,0x66,0x3e,0x06,0x0f, + 0x00,0x00,0x6e,0x3b,0x33,0x30,0x78,0x00, + 0x00,0x00,0x3e,0x60,0x3c,0x06,0x7c,0x00, + 0x08,0x18,0x3e,0x18,0x18,0x1a,0x0c,0x00, + 0x00,0x00,0x66,0x66,0x66,0x66,0x3b,0x00, + 0x00,0x00,0x66,0x66,0x66,0x3c,0x18,0x00, + 0x00,0x00,0x63,0x6b,0x7f,0x7f,0x36,0x00, + 0x00,0x00,0x63,0x36,0x1c,0x36,0x63,0x00, + 0x00,0x00,0x66,0x66,0x66,0x3e,0x06,0x7c, + 0x00,0x00,0x7e,0x4c,0x18,0x32,0x7e,0x00, + 0x0e,0x18,0x18,0x70,0x18,0x18,0x0e,0x00, + 0x0c,0x0c,0x0c,0x00,0x0c,0x0c,0x0c,0x00, + 0x70,0x18,0x18,0x0e,0x18,0x18,0x70,0x00, + 0x3b,0x6e,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x08,0x1c,0x36,0x63,0x63,0x7f,0x00, + 0x3c,0x66,0x60,0x66,0x3c,0x0c,0x06,0x3c, + 0x00,0x66,0x00,0x66,0x66,0x66,0x3f,0x00, + 0x1c,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00, + 0x7e,0xc3,0x3c,0x06,0x3e,0x66,0x3f,0x00, + 0x66,0x00,0x3c,0x06,0x3e,0x66,0x3f,0x00, + 0x70,0x00,0x3c,0x06,0x3e,0x66,0x3f,0x00, + 0x18,0x18,0x3c,0x06,0x3e,0x66,0x3f,0x00, + 0x00,0x00,0x3c,0x60,0x60,0x3c,0x06,0x1c, + 0x7e,0xc3,0x3c,0x66,0x7e,0x60,0x3c,0x00, + 0xcc,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00, + 0x70,0x00,0x3c,0x66,0x7e,0x60,0x3c,0x00, + 0x66,0x00,0x38,0x18,0x18,0x18,0x3c,0x00, + 0x3e,0x63,0x1c,0x0c,0x0c,0x0c,0x1e,0x00, + 0x70,0x00,0x38,0x18,0x18,0x18,0x3c,0x00, + 0x63,0x1c,0x36,0x63,0x7f,0x63,0x63,0x00, + 0x18,0x18,0x00,0x3c,0x66,0x7e,0x66,0x00, + 0x1c,0x00,0xfc,0x60,0x78,0x60,0xfc,0x00, + 0x00,0x00,0x7f,0x0c,0x7f,0xcc,0x7f,0x00, + 0x1f,0x36,0x66,0x7f,0x66,0x66,0x67,0x00, + 0x3c,0x66,0x00,0x3c,0x66,0x66,0x3c,0x00, + 0x00,0x66,0x00,0x3c,0x66,0x66,0x3c,0x00, + 0x00,0x70,0x00,0x3c,0x66,0x66,0x3c,0x00, + 0x3c,0x66,0x00,0x66,0x66,0x66,0x3f,0x00, + 0x00,0x70,0x00,0x66,0x66,0x66,0x3f,0x00, + 0x00,0xcc,0x00,0xcc,0xcc,0x7c,0x0c,0xf8, + 0xc3,0x18,0x3c,0x66,0x66,0x3c,0x18,0x00, + 0x66,0x00,0x66,0x66,0x66,0x66,0x3c,0x00, + 0x0c,0x0c,0x3f,0x60,0x60,0x3f,0x0c,0x0c, + 0x1c,0x36,0x32,0x78,0x30,0x73,0x7e,0x00, + 0x66,0x66,0x3c,0x7e,0x18,0x7e,0x18,0x18, + 0xf8,0xcc,0xcc,0xfa,0xc6,0xcf,0xc6,0xc7, + 0x0e,0x1b,0x18,0x3c,0x18,0x18,0xd8,0x70, + 0x0e,0x00,0x3c,0x06,0x3e,0x66,0x3f,0x00, + 0x1c,0x00,0x38,0x18,0x18,0x18,0x3c,0x00, + 0x00,0x0e,0x00,0x3c,0x66,0x66,0x3c,0x00, + 0x00,0x0e,0x00,0x66,0x66,0x66,0x3f,0x00, + 0x00,0x7c,0x00,0x7c,0x66,0x66,0x66,0x00, + 0x7e,0x00,0x66,0x76,0x7e,0x6e,0x66,0x00, + 0x1e,0x36,0x36,0x1f,0x00,0x3f,0x00,0x00, + 0x1c,0x36,0x36,0x1c,0x00,0x3e,0x00,0x00, + 0x18,0x00,0x18,0x30,0x60,0x66,0x3c,0x00, + 0x00,0x00,0x00,0x7e,0x60,0x60,0x00,0x00, + 0x00,0x00,0x00,0xfc,0x0c,0x0c,0x00,0x00, + 0xc3,0xc6,0xcc,0xde,0x33,0x66,0xcc,0x0f, + 0xc3,0xc6,0xcc,0xdb,0x37,0x6f,0xcf,0x03, + 0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x00, + 0x00,0x33,0x66,0xcc,0x66,0x33,0x00,0x00, + 0x00,0xcc,0x66,0x33,0x66,0xcc,0x00,0x00, + 0x22,0x88,0x22,0x88,0x22,0x88,0x22,0x88, + 0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa, + 0xdb,0x77,0xdb,0xee,0xdb,0x77,0xdb,0xee, + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18, + 0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18, + 0x36,0x36,0x36,0x36,0xf6,0x36,0x36,0x36, + 0x00,0x00,0x00,0x00,0xfe,0x36,0x36,0x36, + 0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18, + 0x36,0x36,0xf6,0x06,0xf6,0x36,0x36,0x36, + 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + 0x00,0x00,0xfe,0x06,0xf6,0x36,0x36,0x36, + 0x36,0x36,0xf6,0x06,0xfe,0x00,0x00,0x00, + 0x36,0x36,0x36,0x36,0xfe,0x00,0x00,0x00, + 0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00, + 0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18, + 0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00, + 0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18, + 0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18, + 0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36, + 0x36,0x36,0x37,0x30,0x3f,0x00,0x00,0x00, + 0x00,0x00,0x3f,0x30,0x37,0x36,0x36,0x36, + 0x36,0x36,0xf7,0x00,0xff,0x00,0x00,0x00, + 0x00,0x00,0xff,0x00,0xf7,0x36,0x36,0x36, + 0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36, + 0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00, + 0x36,0x36,0xf7,0x00,0xf7,0x36,0x36,0x36, + 0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00, + 0x36,0x36,0x36,0x36,0xff,0x00,0x00,0x00, + 0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18, + 0x00,0x00,0x00,0x00,0xff,0x36,0x36,0x36, + 0x36,0x36,0x36,0x36,0x3f,0x00,0x00,0x00, + 0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00, + 0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18, + 0x00,0x00,0x00,0x00,0x3f,0x36,0x36,0x36, + 0x36,0x36,0x36,0x36,0xff,0x36,0x36,0x36, + 0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x00,0x00,0x3b,0x6e,0x64,0x6e,0x3b,0x00, + 0x00,0x3c,0x66,0x7c,0x66,0x7c,0x60,0x60, + 0x00,0x7e,0x66,0x60,0x60,0x60,0x60,0x00, + 0x00,0x7f,0x36,0x36,0x36,0x36,0x36,0x00, + 0x7e,0x66,0x30,0x18,0x30,0x66,0x7e,0x00, + 0x00,0x00,0x3f,0x6c,0x6c,0x6c,0x38,0x00, + 0x00,0x33,0x33,0x33,0x33,0x3e,0x30,0x60, + 0x00,0x3b,0x6e,0x0c,0x0c,0x0c,0x0c,0x00, + 0x7e,0x18,0x3c,0x66,0x66,0x3c,0x18,0x7e, + 0x1c,0x36,0x63,0x7f,0x63,0x36,0x1c,0x00, + 0x1c,0x36,0x63,0x63,0x36,0x36,0x77,0x00, + 0x0e,0x18,0x0c,0x3e,0x66,0x66,0x3c,0x00, + 0x00,0x00,0x7e,0xdb,0xdb,0x7e,0x00,0x00, + 0x06,0x0c,0x7e,0xdb,0xdb,0x7e,0x60,0xc0, + 0x1c,0x30,0x60,0x7c,0x60,0x30,0x1c,0x00, + 0x3c,0x66,0x66,0x66,0x66,0x66,0x66,0x00, + 0x00,0x7e,0x00,0x7e,0x00,0x7e,0x00,0x00, + 0x18,0x18,0x7e,0x18,0x18,0x00,0x7e,0x00, + 0x30,0x18,0x0c,0x18,0x30,0x00,0x7e,0x00, + 0x0c,0x18,0x30,0x18,0x0c,0x00,0x7e,0x00, + 0x0e,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0x18,0xd8,0xd8,0x70, + 0x18,0x18,0x00,0x7e,0x00,0x18,0x18,0x00, + 0x00,0x3b,0x6e,0x00,0x3b,0x6e,0x00,0x00, + 0x1c,0x36,0x36,0x1c,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x0c,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00, + 0x0f,0x0c,0x0c,0x0c,0xec,0x6c,0x3c,0x1c, + 0x78,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00, + 0x70,0x18,0x30,0x60,0x78,0x00,0x00,0x00, + 0x00,0x00,0x3c,0x3c,0x3c,0x3c,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + diff --git a/Src/osmolib/src/target/firmware/display/ssd1783.c b/Src/osmolib/src/target/firmware/display/ssd1783.c new file mode 100644 index 0000000..5696b48 --- /dev/null +++ b/Src/osmolib/src/target/firmware/display/ssd1783.c @@ -0,0 +1,257 @@ +/* Solomon SSD1783 LCD Driver (Epson S1D15G10D08B000 clone) */ + +/* (C) 2010 by Steve Markgraf + * (C) 2010 by Harald Welte + * + * 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 +#include +//#define DEBUG +#include +#include +#include +#include +#include +#include + +#define LCD_COLUMNS 98 +#define LCD_ROWS 67 +#define LCD_TOP_FREE_ROWS 3 +#define LCD_LEFT_FREE_COLS 0 +#define PIXEL_BYTES 3 +#define SSD1783_UWIRE_BITLEN 9 +#define SSD1783_DEV_ID 0 +#define FONT_HEIGHT 8 +#define FONT_WIDTH 8 + +static const uint8_t rgb8_palette[] ={ + 0x00, //P01 Intermediate red tone 000 + 0x03, //P02 Intermediate red tone 001 + 0x05, //P03 Intermediate red tone 010 + 0x07, //P04 Intermediate red tone 011 + 0x09, //P05 Intermediate red tone 100 + 0x0b, //P06 Intermediate red tone 101 + 0x0d, //P07 Intermediate red tone 110 + 0x0f, //P08 Intermediate red tone 111 + 0x00, //P09 Intermediate green tone 000 + 0x03, //P10 Intermediate green tone 001 + 0x05, //P11 Intermediate green tone 010 + 0x07, //P12 Intermediate green tone 011 + 0x09, //P13 Intermediate green tone 100 + 0x0b, //P14 Intermediate green tone 101 + 0x0d, //P15 Intermediate green tone 110 + 0x0f, //P16 Intermediate green tone 111 + 0x00, //P17 Intermediate blue tone 00 + 0x05, //P18 Intermediate blue tone 01 + 0x0a, //P19 Intermediate blue tone 10 + 0x0f, //P20 Intermediate blue tone 11 +}; + +static void ssd1783_cmd_write(const uint8_t cmd) +{ + uint16_t cmd_out = cmd; + uwire_xfer(SSD1783_DEV_ID, SSD1783_UWIRE_BITLEN, &cmd_out, NULL); +} + +static void ssd1783_data_write(const uint8_t data) +{ + uint16_t data_out = ((0x01 << 8) + data); + uwire_xfer(SSD1783_DEV_ID, SSD1783_UWIRE_BITLEN, &data_out, NULL); +} + +static void ssd1783_clrscr(void) +{ + uint16_t i; + + /* Select the whole display area for clearing */ + ssd1783_cmd_write(CMD_PASET); /* Page address set [2] */ + ssd1783_data_write(0x00); /* Start page: 0x00 */ + ssd1783_data_write(LCD_ROWS-1); /* End page */ + ssd1783_cmd_write(CMD_CASET); /* Column address set [2] */ + ssd1783_data_write(0x00); /* Start column: 0x00 */ + ssd1783_data_write((LCD_COLUMNS/2)-1); /* End column (2 pixels per column) */ + ssd1783_cmd_write(CMD_RAMWR); /* Write to memory */ + + /* Fill the display with white */ + for(i=0; i < (LCD_ROWS * (LCD_COLUMNS/2) * PIXEL_BYTES); i++){ + ssd1783_data_write(0xff); + } + ssd1783_cmd_write(CMD_NOP); /* Terminate RAMWR with NOP */ +} + +static void ssd1783_init(void) +{ + unsigned int i; + + calypso_reset_set(RESET_EXT, 0); + uwire_init(); + delay_ms(3); + + /* Begin SSD1783 initialization sequence */ + ssd1783_cmd_write(CMD_OSCON); /* Internal OSC on */ + ssd1783_cmd_write(CMD_SLPOUT); /* Sleep out (Leave sleep mode) */ + + ssd1783_cmd_write(CMD_COMSCN); /* Common scan direction [1] */ + ssd1783_data_write(0x01); /* Scan 1 -> 68, 132 <- 69 */ + ssd1783_cmd_write(CMD_DATCTL); /* Data Scan Direction [3] */ + ssd1783_data_write(0x00); /* Normal page address, normal rotation, + * scan direction in column direction */ + ssd1783_data_write(0x00); /* RGB arrangement: RGB-RGB */ + ssd1783_data_write(0x02); /* Gray-scale setup: 16 gray-scale Type A, 8-bit mode */ + + /* Initialize RGB8 palette for 8-Bit color mode */ + ssd1783_cmd_write(CMD_RGBSET8); /* 256-color position set [20] */ + for(i=0; i < sizeof(rgb8_palette); i++){ + ssd1783_data_write(rgb8_palette[i]); + } + + ssd1783_cmd_write(CMD_DISCTL); /* Display control [3] */ + ssd1783_data_write(0xff); /* no clock division, F1, F2 switching period = field */ + ssd1783_data_write(0x10); /* Drive duty, P24 = 1 */ + ssd1783_data_write(0x01); /* FR inverse set, P30=1 */ + ssd1783_cmd_write(CMD_SCSTART); /* Scroll start set [1] */ + ssd1783_data_write(0x00); /* Start block address 0x00 */ + + /* Turn on the power regulator which generates VLCD */ + ssd1783_cmd_write(CMD_PWRCTR); /* Power Control [1] */ + ssd1783_data_write(0x0b); /* Booster, follower and regulator circuit on */ + + /* FIXME: put this in a separate function (ssd1783_set_contrast) */ + ssd1783_cmd_write(CMD_VOLCTR); /* Electronic Volume Control [2] */ + ssd1783_data_write(0x29); /* Set contrast */ + ssd1783_data_write(0x05); /* Set contrast */ + + ssd1783_cmd_write(CMD_DISINV); /* Invert Display */ + ssd1783_cmd_write(CMD_TMPGRD); /* Temperature gradient set */ + ssd1783_data_write(0x00); /* default temperature gradient (-0.05% / °C) */ + ssd1783_cmd_write(CMD_BIASSET); /* Set biasing ratio [1] */ + ssd1783_data_write(0x03); /* 1/10 bias */ + ssd1783_cmd_write(CMD_FREQSET); /* Set frequency and n-line inversion [2] */ + ssd1783_data_write(0x08); /* frequency: 75Hz (POR) */ + ssd1783_data_write(0x06); /* n-line inversion: 6 lines */ + ssd1783_cmd_write(CMD_RESCMD); /* reserved command in datasheet? */ + ssd1783_cmd_write(CMD_PWMSEL); /* Select PWM/FRC, Full/8 color mode [3] */ + ssd1783_data_write(0x28); /* fixed */ + ssd1783_data_write(0x2c); /* 5 bits PWM + 1 bit FRC (POR) */ + ssd1783_data_write(0x05); /* Full color mode (0x45 would be 8 color powersaving) */ + + ssd1783_cmd_write(CMD_DISON); /* Display ON */ + ssd1783_clrscr(); /* Clear the display */ +} + +extern const unsigned char fontdata_r8x8_horiz[]; + +/* + * Pixel format for 8-bit mode, 12-bit color, 2 Pixel per 3 byte + * D7, D6, D5, D4, D3, D2, D1, D0: RRRRGGGG (8 bits) 1st write + * D7, D6, D5, D4, D3, D2, D1, D0: BBBBRRRR (8 bits) 2nd write + * D7, D6, D5, D4, D3, D2, D1, D0: GGGGBBBB (8 bits) 3rd write +*/ + +static void ssd1783_goto_xy(int xpos, int ypos) +{ + ssd1783_cmd_write(CMD_PASET); + ssd1783_data_write(xpos); + ssd1783_data_write(xpos + (FONT_HEIGHT-1)); + + ssd1783_cmd_write(CMD_CASET); + ssd1783_data_write(ypos); + ssd1783_data_write(ypos + ((FONT_WIDTH/2)-1)); + + ssd1783_cmd_write(CMD_NOP); +} + +static int ssd1783_putc_col(unsigned char c, int fColor, int bColor) +{ + int i, j; + uint8_t cols = FONT_WIDTH; + uint8_t rows = FONT_HEIGHT; + uint8_t row_slice; + uint8_t rowmask; + uint16_t pixel0; /* left pixel */ + uint16_t pixel1; /* right pixel */ + + ssd1783_cmd_write(CMD_RAMWR); + + for (i = 0; i < rows; i++) { + row_slice = fontdata_r8x8_horiz[(FONT_WIDTH * c)+i]; + printd("\nSSD1783 FontData=0x%02hx", row_slice); + rowmask = 0x80; + for (j = 0; j < cols; j += 2) { + if (!(row_slice & rowmask)) + pixel0 = bColor; + else + pixel0 = fColor; + rowmask = rowmask >> 1; + if (!(row_slice & rowmask)) + pixel1 = bColor; + else + pixel1 = fColor; + rowmask = rowmask >> 1; + /* Write the RGB-RGB pixel data */ + ssd1783_data_write((pixel0 >> 4) & 0xff); + ssd1783_data_write(((pixel0 & 0x00f) << 4) | ((pixel1 >> 8) & 0x00f)); + ssd1783_data_write(pixel1 & 0xff); + } + } + ssd1783_cmd_write(CMD_NOP); + + return c; +} + +static int ssd1783_puts_col(const char *str, int txtline, int fColor, int bColor) +{ + int i; + for (i = 0; *str != 0x00; i += (FONT_WIDTH/2)) { + ssd1783_goto_xy(((txtline*FONT_HEIGHT)+LCD_TOP_FREE_ROWS), + (i + LCD_LEFT_FREE_COLS)); + ssd1783_putc_col(*str++, fColor, bColor); + } + + return 0; +} + +/* interface to display driver core */ + +static void ssd1783_set_attr(unsigned long attr) +{ + /* FIXME */ +} + +static int ssd1783_putc(unsigned int c) +{ + return ssd1783_putc_col(c, BLACK, WHITE); +} + +static int ssd1783_puts(const char *str) +{ + return ssd1783_puts_col(str, 0, BLACK, WHITE); +} + +const struct display_driver ssd1783_display = { + .name = "ssd1783", + .init = &ssd1783_init, + .set_attr = &ssd1783_set_attr, + .unset_attr = &ssd1783_set_attr, + .clrscr = &ssd1783_clrscr, + .goto_xy = &ssd1783_goto_xy, + .putc = &ssd1783_putc, + .puts = &ssd1783_puts, +}; diff --git a/Src/osmolib/src/target/firmware/display/ssd1963.c b/Src/osmolib/src/target/firmware/display/ssd1963.c new file mode 100644 index 0000000..49d5275 --- /dev/null +++ b/Src/osmolib/src/target/firmware/display/ssd1963.c @@ -0,0 +1,210 @@ +/* Solomon SSD1963 LCD Driver (probably not exactly the SSD1963) + * as used in the Sony Ericsson J100i */ + +/* (C) 2010-11 by Steve Markgraf + * (C) 2010 by Harald Welte + * + * 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 +#include +#include +#include +#include +#include +#include + +#define LCD_COLUMNS 96 +#define LCD_ROWS 64 +#define LCD_TOP_FREE_ROWS 3 +#define LCD_LEFT_FREE_COLS 0 +#define PIXEL_BYTES 3 +#define SSD1963_UWIRE_BITLEN 9 +#define SSD1963_DEV_ID 0 +#define FONT_HEIGHT 8 +#define FONT_WIDTH 8 + +#define BLACK 0x0000 +#define WHITE 0x0fff + +static void ssd1963_cmd_write(const uint8_t cmd) +{ + uint16_t cmd_out = cmd; + uwire_xfer(SSD1963_DEV_ID, SSD1963_UWIRE_BITLEN, &cmd_out, NULL); +} + +static void ssd1963_data_write(const uint8_t data) +{ + uint16_t data_out = ((0x01 << 8) + data); + uwire_xfer(SSD1963_DEV_ID, SSD1963_UWIRE_BITLEN, &data_out, NULL); +} + +static void ssd1963_clrscr(void) +{ + uint16_t i; + + /* Select the whole display area for clearing */ + ssd1963_cmd_write(0x2b); + ssd1963_data_write(0x00); + ssd1963_data_write(LCD_ROWS-1); + + ssd1963_cmd_write(0x2a); + ssd1963_data_write(0x00); + ssd1963_data_write(LCD_COLUMNS-1); + + ssd1963_cmd_write(0x2c); + + /* Fill the display with white */ + for(i=0; i < (LCD_ROWS * (LCD_COLUMNS/2) * PIXEL_BYTES); i++){ + ssd1963_data_write(0xff); + } +} + +static void ssd1963_init(void) +{ + unsigned int i; + + calypso_reset_set(RESET_EXT, 0); + uwire_init(); + delay_ms(3); + + /* Begin SSD1963 initialization sequence */ + ssd1963_cmd_write(0xb6); /* Set vertical period */ + ssd1963_data_write(0x4b); + ssd1963_data_write(0xf1); + ssd1963_data_write(0x40); + ssd1963_data_write(0x40); + ssd1963_data_write(0x00); + ssd1963_data_write(0x8c); + ssd1963_data_write(0x00); + + ssd1963_cmd_write(0x3a); /* Set pixel format */ + ssd1963_data_write(0x03); /* 0x03: 12 bit, 0x05: 16 Bit / pixel */ + ssd1963_cmd_write(0x11); + + /* Contrast/Electronic Volume Control */ + ssd1963_cmd_write(0xba); + ssd1963_data_write(0x5b); + ssd1963_data_write(0x84); + + ssd1963_cmd_write(0x36); + ssd1963_data_write(0x00); + + ssd1963_cmd_write(0x13); /* Enter normal mode */ + ssd1963_clrscr(); + + ssd1963_cmd_write(0x29); /* Display ON */ +} + +extern const unsigned char fontdata_r8x8_horiz[]; + +/* + * Pixel format for 8-bit mode, 12-bit color, 2 Pixel per 3 byte + * D7, D6, D5, D4, D3, D2, D1, D0: RRRRGGGG (8 bits) 1st write + * D7, D6, D5, D4, D3, D2, D1, D0: BBBBRRRR (8 bits) 2nd write + * D7, D6, D5, D4, D3, D2, D1, D0: GGGGBBBB (8 bits) 3rd write +*/ + +static void ssd1963_goto_xy(int xpos, int ypos) +{ + ssd1963_cmd_write(0x2b); + ssd1963_data_write(xpos); + ssd1963_data_write(xpos + FONT_HEIGHT-1); + + ssd1963_cmd_write(0x2a); + ssd1963_data_write(ypos); + ssd1963_data_write(ypos + FONT_WIDTH-1); +} + +static int ssd1963_putc_col(unsigned char c, int fColor, int bColor) +{ + int i, j; + uint8_t cols = FONT_WIDTH; + uint8_t rows = FONT_HEIGHT; + uint8_t row_slice; + uint8_t rowmask; + uint16_t pixel0; /* left pixel */ + uint16_t pixel1; /* right pixel */ + + ssd1963_cmd_write(0x2c); + + for (i = 0; i < rows; i++) { + row_slice = fontdata_r8x8_horiz[(FONT_WIDTH * c)+i]; + rowmask = 0x80; + for (j = 0; j < cols; j += 2) { + if (!(row_slice & rowmask)) + pixel0 = bColor; + else + pixel0 = fColor; + rowmask = rowmask >> 1; + if (!(row_slice & rowmask)) + pixel1 = bColor; + else + pixel1 = fColor; + rowmask = rowmask >> 1; + /* Write the RGB-RGB pixel data */ + ssd1963_data_write((pixel0 >> 4) & 0xff); + ssd1963_data_write(((pixel0 & 0x00f) << 4) | ((pixel1 >> 8) & 0x00f)); + ssd1963_data_write(pixel1 & 0xff); + } + } + ssd1963_cmd_write(0x00); + + return c; +} + +static int ssd1963_puts_col(const char *str, int txtline, int fColor, int bColor) +{ + int i; + for (i = 0; *str != 0x00; i += FONT_WIDTH) { + ssd1963_goto_xy(((txtline*FONT_HEIGHT)+LCD_TOP_FREE_ROWS), + (i + LCD_LEFT_FREE_COLS)); + ssd1963_putc_col(*str++, fColor, bColor); + } + + return 0; +} + +/* interface to display driver core */ + +static void ssd1963_set_attr(unsigned long attr) +{ + /* FIXME */ +} + +static int ssd1963_putc(unsigned int c) +{ + return ssd1963_putc_col(c, BLACK, WHITE); +} + +static int ssd1963_puts(const char *str) +{ + return ssd1963_puts_col(str, 0, BLACK, WHITE); +} + +const struct display_driver ssd1963_display = { + .name = "ssd1963", + .init = &ssd1963_init, + .set_attr = &ssd1963_set_attr, + .unset_attr = &ssd1963_set_attr, + .clrscr = &ssd1963_clrscr, + .goto_xy = &ssd1963_goto_xy, + .putc = &ssd1963_putc, + .puts = &ssd1963_puts, +}; diff --git a/Src/osmolib/src/target/firmware/display/st7558.c b/Src/osmolib/src/target/firmware/display/st7558.c new file mode 100644 index 0000000..b92c2de --- /dev/null +++ b/Src/osmolib/src/target/firmware/display/st7558.c @@ -0,0 +1,121 @@ +/* Sitronix ST7558 LCD Driver */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include +#include + +#define MORE_CONTROL 0x80 +#define CONTROL_RS_RAM 0x40 +#define CONTROL_RS_CMD 0x00 +#define Y_ADDR(n) (0x40|((n)&0xf)) +#define X_ADDR(n) (0x80|((n)&0x3f)) + +static const uint8_t setup[] = { CONTROL_RS_CMD, 0x2e, 0x21, 0x12, 0xc0, 0x0b, + 0x20, 0x11, 0x00, 0x40, 0x80 }; +static const uint8_t home[] = { CONTROL_RS_CMD, Y_ADDR(0), X_ADDR(0) }; + +/* video modes */ +static const uint8_t invert[] = { CONTROL_RS_CMD, 0x20, 0x0d }; +static const uint8_t normal[] = { CONTROL_RS_CMD, 0x20, 0x0c }; +static const uint8_t off[] = { CONTROL_RS_CMD, 0x20, 0x08 }; + +#define ST7558_SLAVE_ADDR 0x3c +static int st7558_write(const uint8_t *data, int len) +{ + int rc = i2c_write(ST7558_SLAVE_ADDR, data[0], 1, data+1, len-1); + return rc; +} + +static const uint8_t zero16[] = { CONTROL_RS_RAM, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; +static void st7558_clrscr(void) +{ + int i; + + st7558_write(home, sizeof(home)); + + for (i = 0; i < 102*9; i += 16) + st7558_write(zero16, sizeof(zero16)); + + st7558_write(home, sizeof(home)); +} + +static void st7558_init(void) +{ + /* Release nRESET */ + calypso_reset_set(RESET_EXT, 0); + + i2c_init(0,0); + + st7558_write(setup, sizeof(setup)); + st7558_clrscr(); +} + +static void st7558_set_attr(unsigned long attr) +{ + if (attr & DISP_ATTR_INVERT) + st7558_write(invert, sizeof(invert)); +} + +static void st7558_unset_attr(unsigned long attr) +{ + if (attr & DISP_ATTR_INVERT) + st7558_write(normal, sizeof(normal)); +} + +/* FIXME: we need a mini-libc */ +static void *mcpy(uint8_t *dst, const uint8_t *src, int len) +{ + while (len--) + *dst++ = *src++; + + return dst; +} + +extern const unsigned char fontdata_r8x8[]; + +static void st7558_putc(unsigned char c) +{ + uint8_t putc_buf[16]; + uint8_t bytes_per_char = 8; + + putc_buf[0] = CONTROL_RS_RAM; + mcpy(putc_buf+1, fontdata_r8x8+(c*bytes_per_char), bytes_per_char); + st7558_write(putc_buf, 1+bytes_per_char); +} + +const struct display_driver st7558_display = { + .name = "st7558", + .init = &st7558_init, + .clrscr = &st7558_clrscr, + .set_attr = &st7558_set_attr, + .unset_attr = &st7558_unset_attr, + .putc = &st7558_putc, +}; diff --git a/Src/osmolib/src/target/firmware/display/td014.c b/Src/osmolib/src/target/firmware/display/td014.c new file mode 100644 index 0000000..11ef3ea --- /dev/null +++ b/Src/osmolib/src/target/firmware/display/td014.c @@ -0,0 +1,185 @@ +/* Toppoly TD014 LCD Driver, as used in the Motorola C139/C140 */ + +/* (C) 2010 by Steve Markgraf + * (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include + +#define LCD_COLUMNS 96 +#define LCD_ROWS 64 +#define LCD_TOP_FREE_ROWS 3 +#define LCD_LEFT_FREE_COLS 0 +#define PIXEL_BYTES 2 +#define TD014_UWIRE_BITLEN 9 +#define TD014_DEV_ID 0 +#define FONT_HEIGHT 8 +#define FONT_WIDTH 8 + +#define BLACK 0x0000 +#define WHITE 0xffff + +static void td014_cmd_write(const uint8_t cmd) +{ + uint16_t cmd_out = cmd; + uwire_xfer(TD014_DEV_ID, TD014_UWIRE_BITLEN, &cmd_out, NULL); +} + +static void td014_data_write(const uint8_t data) +{ + uint16_t data_out = ((0x01 << 8) + data); + uwire_xfer(TD014_DEV_ID, TD014_UWIRE_BITLEN, &data_out, NULL); +} + +static void td014_clrscr(void) +{ + uint16_t i; + + /* Select the whole display area for clearing */ + td014_cmd_write(0x10); + td014_data_write(0x00); + td014_cmd_write(0x11); + td014_data_write(0x00); + td014_cmd_write(0x12); + td014_data_write(LCD_COLUMNS-1); + td014_cmd_write(0x13); + td014_data_write(LCD_ROWS-1); + td014_cmd_write(0x14); + td014_data_write(0x00); + td014_cmd_write(0x15); + td014_data_write(0x00); + + /* Fill the display with white */ + for(i=0; i < (LCD_ROWS * LCD_COLUMNS * PIXEL_BYTES); i++) { + td014_data_write(0xff); + } +} + +static void td014_init(void) +{ + calypso_reset_set(RESET_EXT, 0); + uwire_init(); + delay_ms(3); + + td014_cmd_write(0x3f); + td014_data_write(0x01); + td014_cmd_write(0x20); + td014_data_write(0x03); + td014_cmd_write(0x31); + td014_data_write(0x03); + + td014_clrscr(); + +} + +extern const unsigned char fontdata_r8x8_horiz[]; + +static void td014_goto_xy(int xpos, int ypos) +{ + td014_cmd_write(0x10); + td014_data_write(ypos); + td014_cmd_write(0x11); + td014_data_write(xpos); + td014_cmd_write(0x12); + td014_data_write(ypos + FONT_HEIGHT-1); + td014_cmd_write(0x13); + td014_data_write(xpos + FONT_WIDTH-1); + td014_cmd_write(0x14); + td014_data_write(ypos); + td014_cmd_write(0x15); + td014_data_write(xpos); + +} + + /* RGB 556 Byte 1 | Byte 2 * + * Pixel format: RRRRRGGG|GGBBBBBB */ + +static int td014_putc_col(unsigned char c, int fColor, int bColor) +{ + int i, j; + uint8_t cols = FONT_WIDTH; + uint8_t rows = FONT_HEIGHT; + uint8_t row_slice; + uint8_t rowmask; + uint16_t pixel; + + for (i = 0; i < rows; i++) { + row_slice = fontdata_r8x8_horiz[(FONT_WIDTH * c)+i]; + rowmask = 0x80; + for (j = 0; j < cols; j++) { + if (!(row_slice & rowmask)) + pixel = bColor; + else + pixel = fColor; + rowmask = rowmask >> 1; + /* Write the pixel data */ + td014_data_write((pixel >> 8) & 0xff); + td014_data_write(pixel & 0xff); + } + } + return c; +} + +static int td014_puts_col(const char *str, int txtline, int fColor, int bColor) +{ + int i; + for (i = 0; *str != 0x00; i += FONT_WIDTH) { + td014_goto_xy(((txtline*FONT_HEIGHT)+LCD_TOP_FREE_ROWS), + (i + LCD_LEFT_FREE_COLS)); + td014_putc_col(*str++, fColor, bColor); + } + + return 0; +} + +/* interface to display driver core */ + +static void td014_set_attr(unsigned long attr) +{ + /* FIXME */ +} + +static int td014_putc(unsigned int c) +{ + return td014_putc_col(c, BLACK, WHITE); +} + +static int td014_puts(const char *str) +{ + return td014_puts_col(str, 0, BLACK, WHITE); +} + +const struct display_driver td014_display = { + .name = "td014", + .init = &td014_init, + .set_attr = &td014_set_attr, + .unset_attr = &td014_set_attr, + .clrscr = &td014_clrscr, + .goto_xy = &td014_goto_xy, + .putc = &td014_putc, + .puts = &td014_puts, +}; diff --git a/Src/osmolib/src/target/firmware/flash/cfi_flash.c b/Src/osmolib/src/target/firmware/flash/cfi_flash.c new file mode 100644 index 0000000..69369d5 --- /dev/null +++ b/Src/osmolib/src/target/firmware/flash/cfi_flash.c @@ -0,0 +1,574 @@ +/* NOR Flash Driver for Intel 28F160C3 NOR flash */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include +#include +#include +#include +#include + +/* 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_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) { + /* we only support intel devices */ + 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/osmolib/src/target/firmware/include/abb/twl3025.h b/Src/osmolib/src/target/firmware/include/abb/twl3025.h new file mode 100644 index 0000000..2cd35a5 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/abb/twl3025.h @@ -0,0 +1,136 @@ +#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 + +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/osmolib/src/target/firmware/include/arm.h b/Src/osmolib/src/target/firmware/include/arm.h new file mode 100644 index 0000000..272c9c3 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/arpa/inet.h b/Src/osmolib/src/target/firmware/include/arpa/inet.h new file mode 100644 index 0000000..9a4dd5c --- /dev/null +++ b/Src/osmolib/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 diff --git a/Src/osmolib/src/target/firmware/include/asm/assembler.h b/Src/osmolib/src/target/firmware/include/asm/assembler.h new file mode 100644 index 0000000..cd03e98 --- /dev/null +++ b/Src/osmolib/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 + +/* + * 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/osmolib/src/target/firmware/include/asm/atomic.h b/Src/osmolib/src/target/firmware/include/asm/atomic.h new file mode 100644 index 0000000..19e8ce6 --- /dev/null +++ b/Src/osmolib/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 +#include + +#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/osmolib/src/target/firmware/include/asm/bitops.h b/Src/osmolib/src/target/firmware/include/asm/bitops.h new file mode 100644 index 0000000..337d800 --- /dev/null +++ b/Src/osmolib/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 + +#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 + +/* + * 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 +#include +#include +#include + +#include + +#include +#include +#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/osmolib/src/target/firmware/include/asm/div64.h b/Src/osmolib/src/target/firmware/include/asm/div64.h new file mode 100644 index 0000000..3682616 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/asm/div64.h @@ -0,0 +1,48 @@ +#ifndef __ASM_ARM_DIV64 +#define __ASM_ARM_DIV64 + +#include + +/* + * 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/osmolib/src/target/firmware/include/asm/linkage.h b/Src/osmolib/src/target/firmware/include/asm/linkage.h new file mode 100644 index 0000000..ac1c900 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/asm/ptrace.h b/Src/osmolib/src/target/firmware/include/asm/ptrace.h new file mode 100644 index 0000000..f3a654e --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/asm/swab.h b/Src/osmolib/src/target/firmware/include/asm/swab.h new file mode 100644 index 0000000..4640e27 --- /dev/null +++ b/Src/osmolib/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 +#include + +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/osmolib/src/target/firmware/include/asm/system.h b/Src/osmolib/src/target/firmware/include/asm/system.h new file mode 100644 index 0000000..3db0dc7 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/board.h b/Src/osmolib/src/target/firmware/include/board.h new file mode 100644 index 0000000..9783ef3 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/byteorder.h b/Src/osmolib/src/target/firmware/include/byteorder.h new file mode 100644 index 0000000..41edb93 --- /dev/null +++ b/Src/osmolib/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 +#include + +#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/osmolib/src/target/firmware/include/calypso/backlight.h b/Src/osmolib/src/target/firmware/include/calypso/backlight.h new file mode 100644 index 0000000..3a6abd5 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/calypso/buzzer.h b/Src/osmolib/src/target/firmware/include/calypso/buzzer.h new file mode 100644 index 0000000..dcfd3a3 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/calypso/clock.h b/Src/osmolib/src/target/firmware/include/calypso/clock.h new file mode 100644 index 0000000..abcfde1 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/calypso/clock.h @@ -0,0 +1,67 @@ +#ifndef _CALYPSO_CLK_H +#define _CALYPSO_CLK_H + +#include + +#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/osmolib/src/target/firmware/include/calypso/dma.h b/Src/osmolib/src/target/firmware/include/calypso/dma.h new file mode 100644 index 0000000..00b9bde --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/calypso/dsp.h b/Src/osmolib/src/target/firmware/include/calypso/dsp.h new file mode 100644 index 0000000..e4801cb --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/calypso/dsp.h @@ -0,0 +1,41 @@ +#ifndef _CALYPSO_DSP_H +#define _CALYPSO_DSP_H + +#include + +#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/osmolib/src/target/firmware/include/calypso/dsp_api.h b/Src/osmolib/src/target/firmware/include/calypso/dsp_api.h new file mode 100644 index 0000000..f9751f3 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/calypso/du.h b/Src/osmolib/src/target/firmware/include/calypso/du.h new file mode 100644 index 0000000..f2eae09 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/calypso/du.h @@ -0,0 +1,32 @@ +/* Calypso DU (Debug Unit) Driver */ + +/* (C) 2010 by Ingo Albrecht + * + * 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 + +void calypso_du_init(); +void calypso_du_stop(); +void calypsu_du_dump(); + +#endif /* _CALYPSO_DU_H */ diff --git a/Src/osmolib/src/target/firmware/include/calypso/irq.h b/Src/osmolib/src/target/firmware/include/calypso/irq.h new file mode 100644 index 0000000..5ea5979 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/calypso/l1_environment.h b/Src/osmolib/src/target/firmware/include/calypso/l1_environment.h new file mode 100644 index 0000000..d4d442c --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/calypso/l1_environment.h @@ -0,0 +1,385 @@ +#include + +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/osmolib/src/target/firmware/include/calypso/misc.h b/Src/osmolib/src/target/firmware/include/calypso/misc.h new file mode 100644 index 0000000..4e48093 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/calypso/rtc.h b/Src/osmolib/src/target/firmware/include/calypso/rtc.h new file mode 100644 index 0000000..17528d0 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/calypso/sim.h b/Src/osmolib/src/target/firmware/include/calypso/sim.h new file mode 100644 index 0000000..b2a2164 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/calypso/sim.h @@ -0,0 +1,191 @@ +/* Driver for Simcard Controller inside TI Calypso/Iota */ + +/* (C) 2010 by Philipp Fabian Benedikt Maier + * + * 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_DEBUG_OUTPUTDELAY 200 /* Output delay to minimize stress with some uart bugs */ +#define SIM_DEBUG 0 /* 0=Debug messages are off / 1=Debug messages are on */ +#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 */ + +/* Transceive T0 Apdu to sim acording to GSM 11.11 Page 34 */ +int calypso_sim_transceive(uint8_t cla, /* Class (in GSM context mostly 0xA0 */ + uint8_t ins, /* Instruction */ + uint8_t p1, /* First parameter */ + uint8_t p2, /* Second parameter */ + uint8_t p3le, /* Length of the data that should be transceived */ + uint8_t *data, /* Data payload */ + uint8_t *status, /* Status word (2 byte array, see note 1) */ + uint8_t mode); /* Mode of operation: 1=GET, 0=PUT */ + + /* Note 1: You can use a null-pointer (0) if you are not interested in + the status word */ + +/* Transmission of raw data */ +int calypso_sim_receive(uint8_t *data); /* Receive raw data through the sim interface */ +int calypso_sim_transmit(uint8_t *data, int length); /* Transmit raw data through the sim interface */ + +void calypso_sim_init(void); /* Initialize simcard interface */ + + +/* Known Bugs: + 1.) After powering down the simcard communication stops working +*/ + +#endif /* _CALYPSO_SIM_H */ diff --git a/Src/osmolib/src/target/firmware/include/calypso/timer.h b/Src/osmolib/src/target/firmware/include/calypso/timer.h new file mode 100644 index 0000000..694e4eb --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/calypso/tpu.h b/Src/osmolib/src/target/firmware/include/calypso/tpu.h new file mode 100644 index 0000000..3b1b600 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/calypso/tsp.h b/Src/osmolib/src/target/firmware/include/calypso/tsp.h new file mode 100644 index 0000000..d58a562 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/comm/msgb.h b/Src/osmolib/src/target/firmware/include/comm/msgb.h new file mode 100644 index 0000000..10cff9b --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/comm/msgb.h @@ -0,0 +1,161 @@ +#ifndef _MSGB_H +#define _MSGB_H + +/* (C) 2008-2010 by Harald Welte + * 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 +#include + +struct msgb { + struct llist_head list; + + /* the layer 1 header, if any */ + unsigned char *l1h; + /* the A-bis layer 2 header: OML, RSL(RLL), NS */ + unsigned char *l2h; + /* the layer 3 header. For OML: FOM; RSL: 04.08; GPRS: BSSGP */ + unsigned char *l3h; + + uint16_t data_len; + uint16_t len; + + unsigned char *head; /* start of buffer */ + unsigned char *tail; /* end of message */ + unsigned char *data; /* start of message */ + unsigned char _data[0]; +}; + +extern struct msgb *msgb_alloc(uint16_t size, const char *name); +extern void msgb_free(struct msgb *m); +extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg); +extern struct msgb *msgb_dequeue(struct llist_head *queue); +extern void msgb_reset(struct msgb *m); + +#define msgb_l1(m) ((void *)(m->l1h)) +#define msgb_l2(m) ((void *)(m->l2h)) +#define msgb_l3(m) ((void *)(m->l3h)) + +static inline unsigned int msgb_l1len(const struct msgb *msgb) +{ + return msgb->tail - (uint8_t *)msgb_l1(msgb); +} + +static inline unsigned int msgb_l2len(const struct msgb *msgb) +{ + return msgb->tail - (uint8_t *)msgb_l2(msgb); +} + +static inline unsigned int msgb_l3len(const struct msgb *msgb) +{ + return msgb->tail - (uint8_t *)msgb_l3(msgb); +} + +static inline unsigned int msgb_headlen(const struct msgb *msgb) +{ + return msgb->len - msgb->data_len; +} +static inline int msgb_tailroom(const struct msgb *msgb) +{ + return (msgb->head + msgb->data_len) - msgb->tail; +} +static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len) +{ + unsigned char *tmp = msgb->tail; + + /* we intentionally call cons_puts() here to display an allocation + * failure on the _other_ serial port (i.e. the one that doesn't + * have the HDLC layer on it */ + if (msgb_tailroom(msgb) < len) + cons_puts("msgb_tailroom insufficient!\n"); + + msgb->tail += len; + msgb->len += len; + return tmp; +} +static inline void msgb_put_u8(struct msgb *msgb, uint8_t word) +{ + uint8_t *space = msgb_put(msgb, 1); + space[0] = word & 0xFF; +} +static inline void msgb_put_u16(struct msgb *msgb, uint16_t word) +{ + uint8_t *space = msgb_put(msgb, 2); + space[0] = word >> 8 & 0xFF; + space[1] = word & 0xFF; +} +static inline void msgb_put_u32(struct msgb *msgb, uint32_t word) +{ + uint8_t *space = msgb_put(msgb, 4); + space[0] = word >> 24 & 0xFF; + space[1] = word >> 16 & 0xFF; + space[2] = word >> 8 & 0xFF; + space[3] = word & 0xFF; +} +static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len) +{ + unsigned char *tmp = msgb->data; + msgb->data += len; + msgb->len -= len; + return tmp; +} +static inline uint8_t msgb_get_u8(struct msgb *msgb) +{ + uint8_t *space = msgb_get(msgb, 1); + return space[0]; +} +static inline uint16_t msgb_get_u16(struct msgb *msgb) +{ + uint8_t *space = msgb_get(msgb, 2); + return space[0] << 8 | space[1]; +} +static inline uint32_t msgb_get_u32(struct msgb *msgb) +{ + uint8_t *space = msgb_get(msgb, 4); + return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3]; +} +static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len) +{ + msgb->data -= len; + msgb->len += len; + return msgb->data; +} +static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len) +{ + msgb->len -= len; + return msgb->data += len; +} + +/* increase the headroom of an empty msgb, reducing the tailroom */ +static inline void msgb_reserve(struct msgb *msg, int len) +{ + msg->data += len; + msg->tail += len; +} + +static inline struct msgb *msgb_alloc_headroom(int size, int headroom, + const char *name) +{ + struct msgb *msg = msgb_alloc(size, name); + if (msg) + msgb_reserve(msg, headroom); + return msg; +} + +#endif /* _MSGB_H */ diff --git a/Src/osmolib/src/target/firmware/include/comm/sercomm.h b/Src/osmolib/src/target/firmware/include/comm/sercomm.h new file mode 100644 index 0000000..54256b5 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/comm/sercomm.h @@ -0,0 +1,57 @@ +#ifndef _SERCOMM_H +#define _SERCOMM_H + +/* SERCOMM layer on UART1 (modem UART) */ + +#include + +#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/osmolib/src/target/firmware/include/comm/sercomm_cons.h b/Src/osmolib/src/target/firmware/include/comm/sercomm_cons.h new file mode 100644 index 0000000..11f6654 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/comm/timer.h b/Src/osmolib/src/target/firmware/include/comm/timer.h new file mode 100644 index 0000000..db7d1a5 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/comm/timer.h @@ -0,0 +1,76 @@ +/* + * (C) 2008, 2009 by Holger Hans Peter Freyther + * 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 + +#include + +/** + * Timer management: + * - Create a struct osmo_timer_list + * - Fill out timeout and use add_timer or + * use schedule_timer to schedule a timer in + * x seconds and microseconds from now... + * - Use del_timer 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 + * - update_timers 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 add_timer(struct osmo_timer_list *timer); +void schedule_timer(struct osmo_timer_list *timer, int miliseconds); +void del_timer(struct osmo_timer_list *timer); +int timer_pending(struct osmo_timer_list *timer); + + +/** + * internal timer list management + */ +void prepare_timers(void); +int update_timers(void); +int timer_check(void); + +void timer_init(void); + +#endif diff --git a/Src/osmolib/src/target/firmware/include/console.h b/Src/osmolib/src/target/firmware/include/console.h new file mode 100644 index 0000000..7146e99 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/ctors.h b/Src/osmolib/src/target/firmware/include/ctors.h new file mode 100644 index 0000000..ee4c7b3 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/ctype.h b/Src/osmolib/src/target/firmware/include/ctype.h new file mode 100644 index 0000000..afa3639 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/debug.h b/Src/osmolib/src/target/firmware/include/debug.h new file mode 100644 index 0000000..27c4185 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/defines.h b/Src/osmolib/src/target/firmware/include/defines.h new file mode 100644 index 0000000..3c8732f --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/delay.h b/Src/osmolib/src/target/firmware/include/delay.h new file mode 100644 index 0000000..0d6f3ef --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/display.h b/Src/osmolib/src/target/firmware/include/display.h new file mode 100644 index 0000000..3941b8c --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/display.h @@ -0,0 +1,49 @@ +#ifndef _DISPLAY_DRIVER_H +#define _DISPLAY_DRIVER_H + +enum display_attr { + DISP_ATTR_INVERT = 0x0001, +}; + +struct display_driver { + char *name; + void (*init)(void); + void (*set_attr)(unsigned long attr); + void (*unset_attr)(unsigned long attr); + void (*clrscr)(void); + void (*goto_xy)(int xpos, int ypos); + void (*set_color)(int fgcolor, int bgcolor); + int (*putc)(unsigned char c); + int (*puts)(const char *str); +}; + +extern struct display_driver *display; + +static inline void display_init(void) +{ + display->init(); +} +static inline void display_set_attr(unsigned long attr) +{ + display->set_attr(attr); +} +static inline void display_unset_attr(unsigned long attr) +{ + display->unset_attr(attr); +} +static inline void display_clrscr(void) +{ + display->clrscr(); +} +static inline int display_putchar(unsigned char c) +{ + return display->putc(c); +} +int display_puts(const char *s); + +extern const struct display_driver st7558_display; +extern const struct display_driver ssd1783_display; +extern const struct display_driver ssd1963_display; +extern const struct display_driver td014_display; + +#endif diff --git a/Src/osmolib/src/target/firmware/include/display/ssd1783.h b/Src/osmolib/src/target/firmware/include/display/ssd1783.h new file mode 100644 index 0000000..c72eeba --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/display/ssd1783.h @@ -0,0 +1,56 @@ +#ifndef _SSD1783_H +#define _SSD1783_H + +/* Some basic colors */ +#define RED 0x0f00 +#define GREEN 0x00f0 +#define BLUE 0x000f +#define YELLOW 0x0ff0 +#define MAGENTA 0x0f0f +#define CYAN 0x00ff +#define BLACK 0x0000 +#define WHITE 0x0fff + +/* Epson S1D15G10D08B000 commandset */ +#define CMD_DISON 0xaf // Display on +#define CMD_DISOFF 0xae // Display off +#define CMD_DISNOR 0xa6 // Normal display +#define CMD_DISINV 0xa7 // Inverse display +#define CMD_COMSCN 0xbb // Common scan direction +#define CMD_DISCTL 0xca // Display control +#define CMD_SLPIN 0x95 // Sleep in +#define CMD_SLPOUT 0x94 // Sleep out +#define CMD_PASET 0x75 // Page address set +#define CMD_CASET 0x15 // Column address set +#define CMD_DATCTL 0xbc // Data scan direction, etc. +#define CMD_RGBSET8 0xce // 256-color position set +#define CMD_RAMWR 0x5c // Writing to memory +#define CMD_RAMRD 0x5d // Reading from memory +#define CMD_PTLIN 0xa8 // Partial display in +#define CMD_PTLOUT 0xa9 // Partial display out +#define CMD_RMWIN 0xe0 // Read and modify write +#define CMD_RMWOUT 0xee // End +#define CMD_ASCSE 0xaa // Area scroll set +#define CMD_SCSTART 0xab // Scroll start set +#define CMD_OSCON 0xd1 // Internal oscillation on +#define CMD_OSCOFF 0xd2 // Internal oscillation off +#define CMD_PWRCTR 0x20 // Power control +#define CMD_VOLCTR 0x81 // Electronic volume control +#define CMD_VOLUP 0xd6 // Increment electronic control by 1 +#define CMD_VOLDOWN 0xd7 // Decrement electronic control by 1 +#define CMD_TMPGRD 0x82 // Temperature gradient set +#define CMD_EPCTIN 0xcd // Control EEPROM +#define CMD_EPCOUT 0xcc // Cancel EEPROM control +#define CMD_EPMWR 0xfc // Write into EEPROM +#define CMD_EPMRD 0xfd // Read from EEPROM +#define CMD_EPSRRD1 0x7c // Read register 1 +#define CMD_EPSRRD2 0x7d // Read register 2 +#define CMD_NOP 0x25 // NOP instruction + +/* Extended SSD1783 commandset, partly (also has HW graphic functionalities) */ +#define CMD_BIASSET 0xfb // Set bias ratio +#define CMD_FREQSET 0xf2 // Set frequency and n-line inversion +#define CMD_RESCMD 0xa2 // reserved command +#define CMD_PWMSEL 0xf7 // Select PWM/FRC, Full/8 color mode + +#endif diff --git a/Src/osmolib/src/target/firmware/include/flash/cfi_flash.h b/Src/osmolib/src/target/firmware/include/flash/cfi_flash.h new file mode 100644 index 0000000..9d8b33a --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/flash/cfi_flash.h @@ -0,0 +1,41 @@ + +#ifndef _CFI_FLASH_H +#define _CFI_FLASH_H + +#include + +#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/osmolib/src/target/firmware/include/i2c.h b/Src/osmolib/src/target/firmware/include/i2c.h new file mode 100644 index 0000000..37097a8 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/keypad.h b/Src/osmolib/src/target/firmware/include/keypad.h new file mode 100644 index 0000000..e2e6519 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/layer1/afc.h b/Src/osmolib/src/target/firmware/include/layer1/afc.h new file mode 100644 index 0000000..8b43f8a --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/layer1/agc.h b/Src/osmolib/src/target/firmware/include/layer1/agc.h new file mode 100644 index 0000000..2b7e46e --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/layer1/apc.h b/Src/osmolib/src/target/firmware/include/layer1/apc.h new file mode 100644 index 0000000..3d73c23 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/layer1/async.h b/Src/osmolib/src/target/firmware/include/layer1/async.h new file mode 100644 index 0000000..a9fa08d --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/layer1/async.h @@ -0,0 +1,59 @@ +#ifndef _L1_ASYNC_H +#define _L1_ASYNC_H + +#include + +#include + +#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 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/osmolib/src/target/firmware/include/layer1/avg.h b/Src/osmolib/src/target/firmware/include/layer1/avg.h new file mode 100644 index 0000000..6c5de17 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/layer1/l23_api.h b/Src/osmolib/src/target/firmware/include/layer1/l23_api.h new file mode 100644 index 0000000..9b10b62 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/layer1/l23_api.h @@ -0,0 +1,15 @@ +#ifndef _L1_L23_API_H +#define _L1_L23_API_H + +#include +#include +#include + +void l1a_l23api_init(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); + +void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type); + +#endif /* _L1_L23_API_H */ diff --git a/Src/osmolib/src/target/firmware/include/layer1/mframe_sched.h b/Src/osmolib/src/target/firmware/include/layer1/mframe_sched.h new file mode 100644 index 0000000..3b2039a --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/layer1/mframe_sched.h @@ -0,0 +1,67 @@ +#ifndef _L1_MFRAME_SCHED_H +#define _L1_MFRAME_SCHED_H + +#include + +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, + 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/osmolib/src/target/firmware/include/layer1/prim.h b/Src/osmolib/src/target/firmware/include/layer1/prim.h new file mode 100644 index 0000000..30c51ae --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/layer1/prim.h @@ -0,0 +1,34 @@ +#ifndef _L1_PRIM_H +#define _L1_PRIM_H + +#include + +#include + +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/osmolib/src/target/firmware/include/layer1/rfch.h b/Src/osmolib/src/target/firmware/include/layer1/rfch.h new file mode 100644 index 0000000..344523c --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/layer1/sched_gsmtime.h b/Src/osmolib/src/target/firmware/include/layer1/sched_gsmtime.h new file mode 100644 index 0000000..c40359e --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/layer1/sched_gsmtime.h @@ -0,0 +1,24 @@ +#ifndef _L1_SCHED_GSMTIME_H +#define _L1_SCHED_GSMTIME_H + +#include +#include + +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/osmolib/src/target/firmware/include/layer1/sync.h b/Src/osmolib/src/target/firmware/include/layer1/sync.h new file mode 100644 index 0000000..aa03c82 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/layer1/sync.h @@ -0,0 +1,203 @@ +#ifndef _L1_SYNC_H +#define _L1_SYNC_H + +#include +#include +#include +#include +#include + +/* 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 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/osmolib/src/target/firmware/include/layer1/tdma_sched.h b/Src/osmolib/src/target/firmware/include/layer1/tdma_sched.h new file mode 100644 index 0000000..f58d59b --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/layer1/tdma_sched.h @@ -0,0 +1,73 @@ +#ifndef _L1_TDMA_SCHED_H +#define _L1_TDMA_SCHED_H + +#include + +/* 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/osmolib/src/target/firmware/include/layer1/toa.h b/Src/osmolib/src/target/firmware/include/layer1/toa.h new file mode 100644 index 0000000..dea9dd9 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/layer1/tpu_window.h b/Src/osmolib/src/target/firmware/include/layer1/tpu_window.h new file mode 100644 index 0000000..7b146f1 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/manifest.h b/Src/osmolib/src/target/firmware/include/manifest.h new file mode 100644 index 0000000..6c1b202 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/memory.h b/Src/osmolib/src/target/firmware/include/memory.h new file mode 100644 index 0000000..b0a0490 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/mtk/bfe.h b/Src/osmolib/src/target/firmware/include/mtk/bfe.h new file mode 100644 index 0000000..b07f620 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/mtk/bpi.h b/Src/osmolib/src/target/firmware/include/mtk/bpi.h new file mode 100644 index 0000000..8aa8ee5 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/mtk/bsi.h b/Src/osmolib/src/target/firmware/include/mtk/bsi.h new file mode 100644 index 0000000..6f381ce --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/mtk/emi.h b/Src/osmolib/src/target/firmware/include/mtk/emi.h new file mode 100644 index 0000000..1818499 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/mtk/emi.h @@ -0,0 +1,42 @@ +/* + * (C) 2010 by Tieto + * Marcin Mielczarczyk + * + * 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/osmolib/src/target/firmware/include/mtk/mt6139.h b/Src/osmolib/src/target/firmware/include/mtk/mt6139.h new file mode 100644 index 0000000..35458b5 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/mtk/mt6235.h b/Src/osmolib/src/target/firmware/include/mtk/mt6235.h new file mode 100644 index 0000000..fb9d368 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/mtk/mt6235.h @@ -0,0 +1,74 @@ +/* + * (C) 2010 by Tieto + * Marcin Mielczarczyk + * + * 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/osmolib/src/target/firmware/include/mtk/mt6235_sciphone_g2.h b/Src/osmolib/src/target/firmware/include/mtk/mt6235_sciphone_g2.h new file mode 100644 index 0000000..74d9e7b --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/mtk/system.h b/Src/osmolib/src/target/firmware/include/mtk/system.h new file mode 100644 index 0000000..4543029 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/mtk/system.h @@ -0,0 +1,195 @@ +/* + * (C) 2010 by Tieto + * Marcin Mielczarczyk + * + * 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/osmolib/src/target/firmware/include/mtk/tdma_timer.h b/Src/osmolib/src/target/firmware/include/mtk/tdma_timer.h new file mode 100644 index 0000000..dec0a8a --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/rf/trf6151.h b/Src/osmolib/src/target/firmware/include/rf/trf6151.h new file mode 100644 index 0000000..f0891b6 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/rf/trf6151.h @@ -0,0 +1,49 @@ +#ifndef _TRF6151_H +#define _TRF6151_H + +#include + +/* 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 */ +void trf6151_set_arfcn(uint16_t arfcn, int uplink); + +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/osmolib/src/target/firmware/include/rffe.h b/Src/osmolib/src/target/firmware/include/rffe.h new file mode 100644 index 0000000..63a3a4b --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/rffe.h @@ -0,0 +1,35 @@ +#ifndef _RFFE_H +#define _RFFE_H + +#include + +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/osmolib/src/target/firmware/include/spi.h b/Src/osmolib/src/target/firmware/include/spi.h new file mode 100644 index 0000000..0925a9a --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/include/stdint.h b/Src/osmolib/src/target/firmware/include/stdint.h new file mode 100644 index 0000000..627403f --- /dev/null +++ b/Src/osmolib/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 +#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/osmolib/src/target/firmware/include/stdio.h b/Src/osmolib/src/target/firmware/include/stdio.h new file mode 100644 index 0000000..15ed668 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/stdio.h @@ -0,0 +1,52 @@ +#ifndef _STDIO_H +#define _STDIO_H + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ + +#include + +int printf(const char *format, ...); +int sprintf(char *str, const char *format, ...); +int snprintf(char *str, size_t size, const char *format, ...); + +#include + +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 +#define putchar(c) uart_putchar_wait(1, c) +int puts(const char *s); +#endif + +#if 0 +/* regular UART console */ +#include +#define putchar(c) cons_putchar(c) +#define _puts(s) cons_puts(s) +#define ARCH_HAS_CONSOLE +#endif + +#if 1 +/* sercomm based console */ +#include +#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/osmolib/src/target/firmware/include/string.h b/Src/osmolib/src/target/firmware/include/string.h new file mode 100644 index 0000000..f060659 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/string.h @@ -0,0 +1,12 @@ +#ifndef _STRING_H +#define _STRING_H + +#include + +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/osmolib/src/target/firmware/include/swab.h b/Src/osmolib/src/target/firmware/include/swab.h new file mode 100644 index 0000000..61be900 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/swab.h @@ -0,0 +1,297 @@ +#ifndef _LINUX_SWAB_H +#define _LINUX_SWAB_H + +#include +#include +#include + +/* + * 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/osmolib/src/target/firmware/include/uart.h b/Src/osmolib/src/target/firmware/include/uart.h new file mode 100644 index 0000000..81d7a15 --- /dev/null +++ b/Src/osmolib/src/target/firmware/include/uart.h @@ -0,0 +1,32 @@ +#ifndef _UART_H +#define _UART_H + +#include + +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/osmolib/src/target/firmware/include/uwire.h b/Src/osmolib/src/target/firmware/include/uwire.h new file mode 100644 index 0000000..6d34553 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/layer1/Makefile b/Src/osmolib/src/target/firmware/layer1/Makefile new file mode 100644 index 0000000..455a444 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/layer1/afc.c b/Src/osmolib/src/target/firmware/layer1/afc.c new file mode 100644 index 0000000..a51a107 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/afc.c @@ -0,0 +1,130 @@ +/* AFC (Automatic Frequency Correction) Implementation */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include + +#include +#include +#include + +#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/osmolib/src/target/firmware/layer1/agc.c b/Src/osmolib/src/target/firmware/layer1/agc.c new file mode 100644 index 0000000..b72a6e7 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/agc.c @@ -0,0 +1,62 @@ +/* AFC (Automatic Gain Control) Implementation */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include + +#include +#include + +/* 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/osmolib/src/target/firmware/layer1/apc.c b/Src/osmolib/src/target/firmware/layer1/apc.c new file mode 100644 index 0000000..480c760 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/apc.c @@ -0,0 +1,57 @@ +/* APC (Automatic Power Control) Implementation */ + +/* (C) 2010 by Harald Welte + * + * 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 + +#include +#include + +#include + +/* 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/osmolib/src/target/firmware/layer1/async.c b/Src/osmolib/src/target/firmware/layer1/async.c new file mode 100644 index 0000000..cb2a2a8 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/async.c @@ -0,0 +1,159 @@ +/* Asynchronous part of GSM Layer 1 */ + +/* (C) 2010 by Harald Welte + * + * 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 + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +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/osmolib/src/target/firmware/layer1/avg.c b/Src/osmolib/src/target/firmware/layer1/avg.c new file mode 100644 index 0000000..a4bf565 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/avg.c @@ -0,0 +1,57 @@ +/* Averaging Implementation */ + +/* (C) 2010 by Harald Welte + * + * 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 + +#include + +/* 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/osmolib/src/target/firmware/layer1/init.c b/Src/osmolib/src/target/firmware/layer1/init.c new file mode 100644 index 0000000..e7fde23 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/init.c @@ -0,0 +1,73 @@ +/* OsmocomBB Layer1 initialization */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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/osmolib/src/target/firmware/layer1/l23_api.c b/Src/osmolib/src/target/firmware/layer1/l23_api.c new file mode 100644 index 0000000..11f07cd --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/l23_api.c @@ -0,0 +1,633 @@ +/* Synchronous part of GSM Layer 1: API to Layer2+ */ + +/* (C) 2010 by Holger Hans Peter Freyther + * + * 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 +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* the size we will allocate struct msgb* for HDLC */ +#define L3_MSG_HEAD 4 +#define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_traffic_ind) + L3_MSG_HEAD) + +void l1_queue_for_l2(struct msgb *msg) +{ + /* 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 */ + mframe_disable(MF_TASK_NEIGH_PM51); + + /* 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; ih1.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; ih1.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_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]); + printf("L1CTL_NEIGH_PM_REQ new list with %u entries\n", pm_req->n); + l1s.neigh_pm.n = pm_req->n; /* atomic */ + + /* on BCCH enable PM on frame 51 */ + if (l1s.dedicated.type == GSM_DCHAN_NONE) + mframe_enable(MF_TASK_NEIGH_PM51); +} + +/* 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); +} + +/* callback from SERCOMM when L2 sends a message to L1 */ +static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg) +{ + struct l1ctl_hdr *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; + } + +exit_msgbfree: + msgb_free(msg); +exit_nofree: + return; +} + +void l1a_l23api_init(void) +{ + sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb); +} diff --git a/Src/osmolib/src/target/firmware/layer1/mframe_sched.c b/Src/osmolib/src/target/firmware/layer1/mframe_sched.c new file mode 100644 index 0000000..6281c3d --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/mframe_sched.c @@ -0,0 +1,483 @@ +/* GSM Multiframe Scheduler Implementation (on top of TDMA sched) */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include + +#include + +#include + +#include +#include +#include +#include + +/* 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 */ +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] = 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/osmolib/src/target/firmware/layer1/prim_fbsb.c b/Src/osmolib/src/target/firmware/layer1/prim_fbsb.c new file mode 100644 index 0000000..7affd75 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/prim_fbsb.c @@ -0,0 +1,573 @@ +/* Layer 1 - FCCH and SCH burst handling */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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<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/osmolib/src/target/firmware/layer1/prim_freq.c b/Src/osmolib/src/target/firmware/layer1/prim_freq.c new file mode 100644 index 0000000..88bc453 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/prim_freq.c @@ -0,0 +1,112 @@ +/* Layer 1 Frequency redefinition at "starting time" */ + +/* (C) 2010 by Andreas Eversverg + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +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/osmolib/src/target/firmware/layer1/prim_pm.c b/Src/osmolib/src/target/firmware/layer1/prim_pm.c new file mode 100644 index 0000000..c2d85ac --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/prim_pm.c @@ -0,0 +1,238 @@ +/* Layer 1 Power Measurement */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +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_test(1, l1s.pm.range.arfcn_next); + 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, 0); + + /* 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->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/osmolib/src/target/firmware/layer1/prim_rach.c b/Src/osmolib/src/target/firmware/layer1/prim_rach.c new file mode 100644 index 0000000..47f7424 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/prim_rach.c @@ -0,0 +1,159 @@ +/* Layer 1 Random Access Channel Burst */ + +/* (C) 2010 by Dieter Spaar + * (C) 2010 by Harald Welte + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +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, 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/osmolib/src/target/firmware/layer1/prim_rx_nb.c b/Src/osmolib/src/target/firmware/layer1/prim_rx_nb.c new file mode 100644 index 0000000..7eb4548 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/prim_rx_nb.c @@ -0,0 +1,215 @@ +/* Layer 1 - Receiving Normal Bursts */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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/osmolib/src/target/firmware/layer1/prim_tch.c b/Src/osmolib/src/target/firmware/layer1/prim_tch.c new file mode 100644 index 0000000..96858fb --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/prim_tch.c @@ -0,0 +1,752 @@ +/* Layer 1 - TCH */ + +/* (C) 2010 by Dieter Spaar + * (C) 2010 by Sylvain Munaut + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* 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<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; isnr = 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<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<a_dd_0[0] & (1<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, 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<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<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, 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/osmolib/src/target/firmware/layer1/prim_tx_nb.c b/Src/osmolib/src/target/firmware/layer1/prim_tx_nb.c new file mode 100644 index 0000000..3038178 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/prim_tx_nb.c @@ -0,0 +1,173 @@ +/* Layer 1 - Transmit Normal Burst */ + +/* (C) 2010 by Dieter Spaar + * (C) 2010 by Harald Welte + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +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, 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/osmolib/src/target/firmware/layer1/prim_utils.c b/Src/osmolib/src/target/firmware/layer1/prim_utils.c new file mode 100644 index 0000000..c85da71 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/prim_utils.c @@ -0,0 +1,74 @@ +/* Layer 1 Various primitive utilities */ + +/* (C) 2010 by Sylvain Munaut + * + * 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 + +#include +#include + + +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/osmolib/src/target/firmware/layer1/rfch.c b/Src/osmolib/src/target/firmware/layer1/rfch.c new file mode 100644 index 0000000..d0818d0 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/rfch.c @@ -0,0 +1,152 @@ +/* RF Channel utilities */ + +/* (C) 2010 by Sylvain Munaut + * + * 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 + +#include + +#include + + +/* + * 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/osmolib/src/target/firmware/layer1/sched_gsmtime.c b/Src/osmolib/src/target/firmware/layer1/sched_gsmtime.c new file mode 100644 index 0000000..01e22ca --- /dev/null +++ b/Src/osmolib/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 + * + * 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 +#include + +#include +#include + +#include +#include + +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/osmolib/src/target/firmware/layer1/sync.c b/Src/osmolib/src/target/firmware/layer1/sync.c new file mode 100644 index 0000000..36f4297 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/sync.c @@ -0,0 +1,402 @@ +/* Synchronous part of GSM Layer 1 */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by Dieter Spaar + * (C) 2010 by Holger Hans Peter Freyther + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//#define DEBUG_EVERY_TDMA + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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<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/osmolib/src/target/firmware/layer1/tdma_sched.c b/Src/osmolib/src/target/firmware/layer1/tdma_sched.c new file mode 100644 index 0000000..8812992 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/tdma_sched.c @@ -0,0 +1,244 @@ +/* TDMA Scheduler Implementation */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include + +#include +#include +#include + +#include +#include + +#include + +/* 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; inum_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; inum_items; i++) + { + item_i = &bucket->item[seq[i]]; + + for (j=i+1; jnum_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/osmolib/src/target/firmware/layer1/toa.c b/Src/osmolib/src/target/firmware/layer1/toa.c new file mode 100644 index 0000000..7d80d95 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/toa.c @@ -0,0 +1,80 @@ +/* AFC (Automatic Frequency Correction) Implementation */ + +/* (C) 2010 by Harald Welte + * (C) 2011 by Andreas Eversberg + * + * 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 +#include + +#include +#include + +#include +#include +#include + +/* 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/osmolib/src/target/firmware/layer1/tpu_window.c b/Src/osmolib/src/target/firmware/layer1/tpu_window.c new file mode 100644 index 0000000..2fdb048 --- /dev/null +++ b/Src/osmolib/src/target/firmware/layer1/tpu_window.c @@ -0,0 +1,174 @@ +/* TPU window control routines for Layer 1 */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* 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/osmolib/src/target/firmware/lib/Makefile b/Src/osmolib/src/target/firmware/lib/Makefile new file mode 100644 index 0000000..83f9966 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/lib/bitops.h b/Src/osmolib/src/target/firmware/lib/bitops.h new file mode 100644 index 0000000..428c9a6 --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/lib/changebit.S b/Src/osmolib/src/target/firmware/lib/changebit.S new file mode 100644 index 0000000..7c709fb --- /dev/null +++ b/Src/osmolib/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 +#include +#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/osmolib/src/target/firmware/lib/clearbit.S b/Src/osmolib/src/target/firmware/lib/clearbit.S new file mode 100644 index 0000000..cb48f7a --- /dev/null +++ b/Src/osmolib/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 +#include +#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/osmolib/src/target/firmware/lib/console.c b/Src/osmolib/src/target/firmware/lib/console.c new file mode 100644 index 0000000..7135ae2 --- /dev/null +++ b/Src/osmolib/src/target/firmware/lib/console.c @@ -0,0 +1,190 @@ +/* Ringbuffer based serial console layer, imported from OpenPCD */ + +/* (C) 2006-2010 by Harald Welte + * + * 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 +#include +#include +#include + +#include + +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/osmolib/src/target/firmware/lib/copy_template.S b/Src/osmolib/src/target/firmware/lib/copy_template.S new file mode 100644 index 0000000..cab355c --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/lib/ctors.c b/Src/osmolib/src/target/firmware/lib/ctors.c new file mode 100644 index 0000000..982169d --- /dev/null +++ b/Src/osmolib/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/osmolib/src/target/firmware/lib/ctype.c b/Src/osmolib/src/target/firmware/lib/ctype.c new file mode 100644 index 0000000..f373214 --- /dev/null +++ b/Src/osmolib/src/target/firmware/lib/ctype.c @@ -0,0 +1,34 @@ +/* + * linux/lib/ctype.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +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/osmolib/src/target/firmware/lib/delay.c b/Src/osmolib/src/target/firmware/lib/delay.c new file mode 100644 index 0000000..443ca82 --- /dev/null +++ b/Src/osmolib/src/target/firmware/lib/delay.c @@ -0,0 +1,16 @@ +#include + +/* 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/osmolib/src/target/firmware/lib/div64.S b/Src/osmolib/src/target/firmware/lib/div64.S new file mode 100644 index 0000000..7eeef50 --- /dev/null +++ b/Src/osmolib/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 + +#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/osmolib/src/target/firmware/lib/lib1funcs.S b/Src/osmolib/src/target/firmware/lib/lib1funcs.S new file mode 100644 index 0000000..b02a85e --- /dev/null +++ b/Src/osmolib/src/target/firmware/lib/lib1funcs.S @@ -0,0 +1,334 @@ +/* + * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines + * + * Author: Nicolas Pitre + * - 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 +#include + + +.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/osmolib/src/target/firmware/lib/memcpy.S b/Src/osmolib/src/target/firmware/lib/memcpy.S new file mode 100644 index 0000000..2bbd569 --- /dev/null +++ b/Src/osmolib/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 +#include + + .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/osmolib/src/target/firmware/lib/memset.S b/Src/osmolib/src/target/firmware/lib/memset.S new file mode 100644 index 0000000..04e254a --- /dev/null +++ b/Src/osmolib/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 +#include + + .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/osmolib/src/target/firmware/lib/printf.c b/Src/osmolib/src/target/firmware/lib/printf.c new file mode 100644 index 0000000..a4fc687 --- /dev/null +++ b/Src/osmolib/src/target/firmware/lib/printf.c @@ -0,0 +1,19 @@ + +#include +#include + +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/osmolib/src/target/firmware/lib/setbit.S b/Src/osmolib/src/target/firmware/lib/setbit.S new file mode 100644 index 0000000..9009bc1 --- /dev/null +++ b/Src/osmolib/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 +#include +#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/osmolib/src/target/firmware/lib/string.c b/Src/osmolib/src/target/firmware/lib/string.c new file mode 100644 index 0000000..9703652 --- /dev/null +++ b/Src/osmolib/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 + * + * These are buggy as well.. + * + * * Fri Jun 25 1999, Ingo Oeser + * - 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 , + * Matthew Hawkins + * - Kissed strtok() goodbye + */ + +#include +#include +#include + + +#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/osmolib/src/target/firmware/lib/testchangebit.S b/Src/osmolib/src/target/firmware/lib/testchangebit.S new file mode 100644 index 0000000..37c303e --- /dev/null +++ b/Src/osmolib/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 +#include +#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/osmolib/src/target/firmware/lib/testclearbit.S b/Src/osmolib/src/target/firmware/lib/testclearbit.S new file mode 100644 index 0000000..985c399 --- /dev/null +++ b/Src/osmolib/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 +#include +#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/osmolib/src/target/firmware/lib/testsetbit.S b/Src/osmolib/src/target/firmware/lib/testsetbit.S new file mode 100644 index 0000000..4a8a164 --- /dev/null +++ b/Src/osmolib/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 +#include +#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/osmolib/src/target/firmware/lib/vsprintf.c b/Src/osmolib/src/target/firmware/lib/vsprintf.c new file mode 100644 index 0000000..80e8c1a --- /dev/null +++ b/Src/osmolib/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 + * - changed to provide snprintf and vsnprintf functions + * So Feb 1 16:51:32 CET 2004 Juergen Quade + * - scnprintf and vscnprintf + */ + +#include +#include +#include +#include +#include +#include + +#include + +/** + * 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/osmolib/src/target/firmware/rf/mt6139.c b/Src/osmolib/src/target/firmware/rf/mt6139.c new file mode 100644 index 0000000..a9a6d32 --- /dev/null +++ b/Src/osmolib/src/target/firmware/rf/mt6139.c @@ -0,0 +1,205 @@ +/* Driver for RF Transceiver Circuit (MT6139) */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include + +#include +#include + +#include + +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/osmolib/src/target/firmware/rf/trf6151.c b/Src/osmolib/src/target/firmware/rf/trf6151.c new file mode 100644 index 0000000..5360402 --- /dev/null +++ b/Src/osmolib/src/target/firmware/rf/trf6151.c @@ -0,0 +1,601 @@ +/* Driver for RF Transceiver Circuit (TRF6151) */ + +/* (C) 2010 by Harald Welte + * + * 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 +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* #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 uplink) +{ + uint32_t freq_khz; + uint16_t pll_config; + enum trf6151_gsm_band pll_band; + + 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 (uplink == 0) + 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 871 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, 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); +} + -- cgit v1.2.3-55-g7522