├── .gitignore ├── 95-fernvale-test.rules ├── LICENSE ├── Makefile ├── README.md ├── ROM-BACKUP.txt ├── bionic.c ├── cmd-bl.c ├── cmd-hex.c ├── cmd-irq.c ├── cmd-keypad.c ├── cmd-lcd.c ├── cmd-led.c ├── cmd-load.c ├── cmd-peekpoke.c ├── cmd-reboot.c ├── cmd-sleep.c ├── cmd-spi.c ├── emi.c ├── fernly-usb-loader.c ├── fernvale.ld ├── flashrom-fernvale.patch ├── include ├── bionic.h ├── fernvale-bl.h ├── fernvale-clockgate.h ├── fernvale-emi.h ├── fernvale-gpio.h ├── fernvale-kbd.h ├── fernvale-lcd.h ├── fernvale-pll.h ├── fernvale-pmic.h ├── fernvale-spi.h ├── fernvale-usb.h ├── gnu │ └── stubs-soft.h ├── irq.h ├── lcd.h ├── memio.h ├── printf.h ├── scriptic.h ├── serial.h ├── spi.h └── utils.h ├── irq.c ├── irqasm.S ├── lcd.c ├── lib └── libgcc-armv5.a ├── magic.mk ├── main.c ├── memio.c ├── mkenv.mk ├── pcap-parse ├── Makefile ├── mt6261.pcap └── parse-commands.c ├── scriptic.c ├── scriptic ├── enable-psram.S ├── keypad.S ├── set-plls.S ├── spi-blockmode.S └── spi.S ├── serial.c ├── sha1.c ├── sha1.h ├── spi.c ├── start.S ├── usb-loader.S ├── utils.c ├── vectors.c └── vsprintf.c /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.swp 3 | *.swo 4 | *~ 5 | fernly.log 6 | -------------------------------------------------------------------------------- /95-fernvale-test.rules: -------------------------------------------------------------------------------- 1 | ACTION=="add|change", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0e8d", ATTRS{idProduct}=="0003", ENV{ID_MM_DEVICE_IGNORE}="1" 2 | SUBSYSTEM=="tty", ATTRS{idVendor}=="0e8d", ATTRS{idProduct}=="0003", SYMLINK+="fernvale", MODE="0660", RUN+="/home/fernvale/fernly-usb-loader -t /dev/fernvale /home/fernvale/usb-loader.bin /home/fernvale/firmware.bin" 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Sean Cross 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include mkenv.mk 2 | include magic.mk 3 | 4 | CFLAGS = -march=armv5te -mfloat-abi=soft -Wall \ 5 | -Os -ggdb -Iinclude -marm -fno-stack-protector 6 | AFLAGS = 7 | 8 | LDFLAGS = --nostdlib -T fernvale.ld 9 | LIBS = lib/libgcc-armv5.a 10 | 11 | SRC_C = \ 12 | bionic.c \ 13 | cmd-hex.c \ 14 | cmd-irq.c \ 15 | cmd-peekpoke.c \ 16 | cmd-reboot.c \ 17 | cmd-sleep.c \ 18 | cmd-spi.c \ 19 | cmd-led.c \ 20 | cmd-load.c \ 21 | cmd-bl.c \ 22 | cmd-lcd.c \ 23 | cmd-keypad.c \ 24 | emi.c \ 25 | irq.c \ 26 | lcd.c \ 27 | main.c \ 28 | scriptic.c \ 29 | serial.c \ 30 | spi.c \ 31 | utils.c \ 32 | vectors.c \ 33 | vsprintf.c 34 | 35 | SRC_S = \ 36 | scriptic/set-plls.S \ 37 | scriptic/enable-psram.S \ 38 | scriptic/spi.S \ 39 | scriptic/spi-blockmode.S \ 40 | scriptic/keypad.S \ 41 | start.S 42 | 43 | OBJ = $(addprefix $(BUILD)/, $(SRC_S:.S=.o) $(SRC_C:.c=.o)) 44 | 45 | all: $(BUILD)/firmware.bin \ 46 | $(BUILD)/usb-loader.bin \ 47 | $(BUILD)/fernly-usb-loader 48 | clean: 49 | $(RM) -rf $(BUILD) 50 | 51 | $(BUILD)/fernly-usb-loader: fernly-usb-loader.c sha1.c sha1.h 52 | $(CC_NATIVE) fernly-usb-loader.c sha1.c -o $@ 53 | 54 | $(BUILD)/usb-loader.bin: $(BUILD)/usb-loader.o 55 | $(OBJCOPY) -S -O binary $(BUILD)/usb-loader.o $@ 56 | 57 | HEADER_BUILD = $(BUILD)/genhdr 58 | $(BUILD)/firmware.bin: $(BUILD)/firmware.elf 59 | $(OBJCOPY) -S -O binary $(BUILD)/firmware.elf $@ 60 | 61 | $(BUILD)/firmware.elf: $(OBJ) 62 | $(LD) $(LDFLAGS) --entry=reset_handler -o $@ $(OBJ) $(LIBS) 63 | 64 | $(OBJ): $(HEADER_BUILD)/generated.h | $(OBJ_DIRS) 65 | $(HEADER_BUILD)/generated.h: | $(HEADER_BUILD) 66 | touch $@ 67 | 68 | OBJ_DIRS = $(sort $(dir $(OBJ))) scriptic 69 | $(OBJ_DIRS): 70 | $(MKDIR) -p $@ $@/scriptic 71 | $(HEADER_BUILD): 72 | $(MKDIR) -p $@ build/scriptic 73 | -include $(OBJ:.o=.P) 74 | 75 | test: all 76 | novena-usb-hub -d u1 ; sleep 1; novena-usb-hub -e u1 ; sleep 2 77 | $(BUILD)/fernly-usb-loader /dev/fernvale $(BUILD)/usb-loader.bin $(BUILD)/firmware.bin 78 | 79 | shell: all 80 | novena-usb-hub -d u1 ; sleep 1; novena-usb-hub -e u1 ; sleep 2 81 | $(BUILD)/fernly-usb-loader -s /dev/fernvale $(BUILD)/usb-loader.bin $(BUILD)/firmware.bin 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Fernly - Fernvale Reversing OS 2 | ======================================== 3 | 4 | Fernly is a simple operating system designed for use in the reverse engineering 5 | of the Fernvale CPU. It will likely be disposed of when the system has been 6 | understood well enough to implement a full operating system. 7 | 8 | 9 | Setting up cross compilation 10 | ---------------------------- 11 | ### Linux 12 | 13 | git clone https://github.com/robertfoss/setup_codesourcery.git 14 | sudo setup_codesourcery/setup.sh 15 | /usr/local/bin/codesourcery-arm-2014.05.sh 16 | 17 | 18 | Building Fernly 19 | --------------- 20 | 21 | To compile, simply run "make". If you're cross-compiling, set CROSS_COMPILE to 22 | the prefix of your cross compiler. This is very similar to how to compile for Linux. 23 | 24 | For example: 25 | 26 | make CROSS_COMPILE=arm-none-linux-gnueabi- 27 | 28 | 29 | Running Fernly 30 | -------------- 31 | 32 | To run, connect the target device and run the following command: 33 | 34 | ./build/fernly-usb-loader -s /dev/fernvale ./build/usb-loader.bin ./build/firmware.bin 35 | 36 | This will open up /dev/fernvale, load usb-loader.bin as a stage 1 bootloader, 37 | and then load (and jump to) firmware.bin as stage 2. Optionally, you can add 38 | a stage 3 file by specifying it as an additional argument. 39 | 40 | Many 3rd-party devices enter bootloader mode only for a short window (~1s) 41 | after being connected to USB. A device almost certainly should be "off". Some 42 | devices require that battery is removed, while some - don't. To accommodate 43 | such cases, there's -w (wait) option. Run fernly-usb-loader, and only 44 | then connect a device to USB. This will allow to try various combinations 45 | mentioned above with greater comfort (you need to disconnect and poweroff 46 | device after each try, and restart fernly-usb-loader). 47 | 48 | ./build/fernly-usb-loader -w -s /dev/ttyUSB0 ./build/usb-loader.bin ./build/firmware.bin 49 | 50 | Linux Notes 51 | ----------- 52 | 53 | Since Fernvale is based on a Mediatek chip, ModemManager will, by default, 54 | try to treat it as a modem and make it available for network connections. 55 | This is undesirable. 56 | 57 | To work around this problem, create a udev rule under /etc/udev/rules.d/ 58 | called 98-fernvale.rules with the following contents: 59 | 60 | SUBSYSTEM=="tty", ATTRS{idVendor}=="0e8d",\ 61 | ATTRS{idProduct}=="0003",\ 62 | MODE="0660", SYMLINK+="fernvale" 63 | 64 | ACTION=="add|change", SUBSYSTEM=="usb",\ 65 | ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="0e8d",\ 66 | ATTRS{idProduct}=="0003",\ 67 | ENV{ID_MM_DEVICE_IGNORE}="1" 68 | 69 | OSX Notes 70 | --------- 71 | The default OSX CDC matching seems to miss the Fernvale board. Use [fernvale-osx-codeless](https://github.com/jacobrosenthal/fernvale-osx-codeless) to get a com port. 72 | 73 | 74 | SPI and Flashrom 75 | ---------------- 76 | 77 | Fernly includes a special 'flashrom' mode that allows for direct communication 78 | with the flashrom program to manipulate the onboard SPI. The protocol is 79 | binary, and can be entered by issuing the following command: 80 | 81 | spi flashrom 82 | 83 | Fernly will respond with a binary 0x05, indicating it is ready. 84 | 85 | The format of the protocol is very simple. The host writes the number of bytes 86 | to write, then the number of bytes to read, and then writes the data to send 87 | to the flash chip. It then reads the requested number of bytes. For 88 | example, to send a 2-byte command '0xfe 0xfa' followed by a 3-byte response, 89 | write the following data to the serial port: 90 | 91 | | 02 03 fe fa | 92 | 93 | Then read three bytes of data from the serial port. 94 | 95 | A maximum of 255 bytes may be transmitted and received at one time, though 96 | in practice these numbers may be smaller. 97 | 98 | To exit 'spi flashrom' mode and return to fernly, read/write zero bytes. 99 | That is, send the following packet: 100 | 101 | | 00 00 | 102 | 103 | See ROM-BACKUP.txt for user-level instructions how to backup/restore 104 | FlashROM of your device. 105 | 106 | Licensing 107 | --------- 108 | 109 | Fernly is licensed under the BSD 2-clause license (see LICENSE). 110 | 111 | Previous versions of fernly linked against division libraries taken from U-Boot, 112 | which were licensed under GPL-2. These files have been removed. 113 | 114 | Instead, we supply a version of libgcc.a. This file was extracted from a 115 | standard gcc toolchain, specifically: 116 | 117 | https://code.google.com/p/yus-repo/downloads/detail?name=arm-none-eabi-4.6-armv5.tar.gz 118 | 119 | It has not been modified, and its distribution here should be covered under 120 | the "runtime exception". 121 | 122 | 123 | Memory Map 124 | ---------- 125 | 126 | | 0x00000000 | 0x0fffffff | 0x0fffffff | PSRAM map, repeated and mirrored at 0x00800000 offsets | 127 | | ---------- | ---------- | ---------- | ----------------------------------- | 128 | | 0x10000000 | 0x1fffffff | 0x0fffffff | Memory-mapped SPI chip | 129 | | ?????????? | ?????????? | ?????????? | ??????????????????????????????????? | 130 | | 0x70000000 | 0x7000cfff | 0xcfff | On-chip SRAM (maybe cache?) | 131 | | ?????????? | ?????????? | ?????????? | ??????????????????????????????????? | 132 | | 0x80000000 | 0x80000008 | 0x08 | Config block (chip version, etc.) | 133 | | 0x82000000 | 0x82d00000 | ?????????? | Modem system stuff | 134 | | 0x83000000 | 0xa3090000 | ?????????? | Modem peripheral stuff | 135 | | 0x83020000 | | | TDMA unit | 136 | | 0x83050000 | | | Frame Check Sequence unit | 137 | | 0x83060000 | | | GPRS cipher unit | 138 | | 0x83070000 | | | Baseband serial interface | 139 | | 0x83080000 | | | Baseband parallel interface | 140 | | 0xa0000000 | 0xa0000008 | 0x08 | Config block (mirror?) | 141 | | 0xa0010000 | ?????????? | ?????????? | Power, config block | 142 | | 0xa0020000 | 0xa0020e10 | 0x0e10 | GPIO control block | 143 | | 0xa0030000 | 0xa0030040 | 0x40 | WDT block | 144 | | | | | - 0x08 -> WDT register (?) | 145 | | | | | - 0x18 -> Boot src (?) | 146 | | 0xa0030800 | ?????????? | ?????????? | ???????????????????????????? | 147 | | 0xa0040000 | ?????????? | ?????????? | ??????????????????????????????????? | 148 | | 0xa0050000 | ?????????? | ?????????? | External memory block | 149 | | 0xa0060000 | ?????????? | ?????????? | IRQ Controller block | 150 | | 0xa0070000 | ========== | ========== | DMA Controller block | 151 | | 0xa0080000 | 0xa008005c | 0x5c | UART1 block | 152 | | 0xa0090000 | 0xa009005c | 0x5c | UART2 block | 153 | | 0xa00a0000 | ?????????? | ?????????? | ??????????????????????????????????? | 154 | | 0xa00b0000 | 0xa00b006c | 0x6c | Bluetooth interface block | 155 | | 0xa00c0000 | 0xa00c002c | 0x2c | General purpose timer block | 156 | | 0xa00d0000 | 0xa00d0024 | 0x24 | Keypad scanner block | 157 | | 0xa00e0000 | 0xa00e0008 | 0x0c | PWM1 block | 158 | | 0xa00f0000 | 0xa00f00b0 | 0xb0 | SIM1 interface block | 159 | | 0xa0100000 | 0xa01000b0 | 0xb0 | SIM2 interface block | 160 | | 0xa0110000 | ?????????? | ?????????? | SEJ/CHE (Security engine) block | 161 | | 0xa0120000 | 0xa0120074 | 0x74 | I2C block | 162 | | 0xa0130000 | 0xa0130098 | 0x98 | SD1 block (MSDC) | 163 | | 0xa0140000 | ?????????? | ?????????? | Serial flash block | 164 | | 0xa0150000 | ?????????? | ?????????? | ?? MAYBE also SPI ????????????????? | 165 | | 0xa0160000 | ?????????? | ?????????? | Die-to-die master interface | 166 | | 0xa0170000 | ?????????? | ?????????? | Analogue chip controller block | 167 | | 0xa0180000 | ?????????? | ?????????? | TOPSM block | 168 | | 0xa0190000 | 0xa0190310 | 0x58 | HIF (DMA?) interface block | 169 | | 0xa01b0000 | 0xa01b0058 | 0x58 | NLI (arbiter) interface block | 170 | | 0xa01c0000 | ?????????? | ?????????? | EFuse block | 171 | | 0xa01e0000 | ?????????? | ?????????? | SPI block | 172 | | 0xa01f0000 | 0xa01f0060 | 0x60 | OS timer block | 173 | | 0xa0210000 | ?????????? | ?????????? | More analog bits | 174 | | 0xa0220000 | ?????????? | ?????????? | MBist block | 175 | | 0xa0240000 | ?????????? | ?????????? | NAND flash block | 176 | | 0xa0260000 | 0xa0260058 | 0x58 | FSPI (internal FM radio) block | 177 | | 0xa0270000 | 0xa0270098 | 0x98 | SD2 block | 178 | | 0xa0400000 | ?????????? | ?????????? | IMGDMA block | 179 | | 0xa0410000 | ?????????? | ?????????? | IDP RESZ CR2 | 180 | | 0xa0420000 | 0xa04201d8 | 0x01d8 | CAM interface block | 181 | | 0xa0430000 | ?????????? | ?????????? | Serial camera block | 182 | | 0xa0440000 | ?????????? | ?????????? | 2D graphics block | 183 | | 0xa0450000 | ?????????? | ?????????? | LCD interface block | 184 | | 0xa0460000 | ?????????? | ?????????? | Multimedia system BIST block | 185 | | 0xa0470000 | ?????????? | ?????????? | Multimedia colour config block | 186 | | 0xa0480000 | ?????????? | ?????????? | Multimedia system config block | 187 | | 0xa0500000 | ?????????? | ?????????? | ARM configuration block | 188 | | 0xa0510000 | ?????????? | ?????????? | Boot configuration block | 189 | | 0xa0520000 | ?????????? | ?????????? | Code decompression engine block | 190 | | 0xa0530000 | ?????????? | ?????????? | Level 1 cache block | 191 | | 0xa0540000 | ?????????? | ?????????? | MPU config block | 192 | | 0xa0700000 | ?????????? | ?????????? | Power management block. Write (val & 0xfe0f | 0x140) to 0xa0700230 to power off. | 193 | | 0xa0710000 | 0xa0710078 | 0x78 | RTC block | 194 | | 0xa0720000 | ?????????? | ?????????? | Analogue baseband config block | 195 | | 0xa0730000 | 0xa0730100 | ?????? | Analogue die config | 196 | | 0xa0730104 | 0xa073104c | ?????? | GPIO mode / pull control blocks | 197 | | 0xa074000c | 0xa0740014 | 0x0c | PWM2 block | 198 | | 0xa0740018 | 0xa0740020 | 0x0c | PWM3 block | 199 | | 0xa0750000 | 0xa075005c | 0x5c | ADCDET block | 200 | | 0xa0760000 | ?????????? | ?????????? | Analogue IRQ controller | 201 | | 0xa0790000 | 0xa07900d8 | 0xd8 | ADC block | 202 | | 0xa07a0000 | ?????????? | ?????????? | Analogue Die-to-die block | 203 | | 0xa0900000 | 0xa0900240 | ?????????? | USB block | 204 | | 0xa0910000 | ?????????? | ?????????? | ??????????????????????????????????? | 205 | | 0xa0920000 | ?????????? | ?????????? | AHB DMA block | 206 | | 0xa3300000 | 0xa33a0000 | ?????????? | Bluetooth things | 207 | | 0xfff00000 | 0xffffffff | 0x100000 | Boot ROM, mirrored each 64K (its real size) | 208 | -------------------------------------------------------------------------------- /ROM-BACKUP.txt: -------------------------------------------------------------------------------- 1 | Fernly doesn't require changing a firmware stored in FlashROM of 2 | your device - it runs completely from RAM. You may still want 3 | to backup the original firmware for various reasons. Following 4 | gives a walkthru how to do this. 5 | 6 | 1. Check out the latest flashrom HEAD: 7 | 8 | svn co http://code.coreboot.org/svn/flashrom/trunk flashrom 9 | 10 | Using latest HEAD is recommended, as it may have more chip definitions, 11 | and there's less chance it won't recognize your FlashROM. 12 | 13 | 2. Apply flashrom-fernvale.patch from fernly: 14 | 15 | patch -p0 37 | #include 38 | #include "bionic.h" 39 | #include "printf.h" 40 | #include "include/serial.h" 41 | typedef unsigned char u_char; 42 | 43 | /* 44 | * This array is designed for mapping upper and lower case letter 45 | * together for a case independent comparison. The mappings are 46 | * based upon ascii character sequences. 47 | */ 48 | static const u_char charmap[] = { 49 | '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', 50 | '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', 51 | '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', 52 | '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', 53 | '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', 54 | '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', 55 | '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', 56 | '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', 57 | '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', 58 | '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', 59 | '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', 60 | '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', 61 | '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', 62 | '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', 63 | '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', 64 | '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', 65 | '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', 66 | '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', 67 | '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', 68 | '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', 69 | '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', 70 | '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', 71 | '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', 72 | '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', 73 | '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', 74 | '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', 75 | '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', 76 | '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', 77 | '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', 78 | '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', 79 | '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', 80 | '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', 81 | }; 82 | 83 | /* 84 | * Span the string s2 (skip characters that are in s2). 85 | */ 86 | size_t _strspn(const char *s1, const char *s2) 87 | { 88 | const char *p = s1, *spanp; 89 | char c, sc; 90 | 91 | /* 92 | * Skip any characters in s2, excluding the terminating \0. 93 | */ 94 | cont: 95 | c = *p++; 96 | for (spanp = s2; (sc = *spanp++) != 0;) 97 | if (sc == c) 98 | goto cont; 99 | return (p - 1 - s1); 100 | } 101 | 102 | 103 | /* 104 | * Find the first occurrence in s1 of a character in s2 (excluding NUL). 105 | */ 106 | char * _strpbrk(const char *s1, const char *s2) 107 | { 108 | const char *scanp; 109 | int c, sc; 110 | 111 | while ((c = *s1++) != 0) { 112 | for (scanp = s2; (sc = *scanp++) != 0;) 113 | if (sc == c) 114 | return ((char *)(s1 - 1)); 115 | } 116 | return (NULL); 117 | } 118 | 119 | char *_strtok(char *str, const char *delim, char **saveptr) { 120 | char *token; 121 | if (str) 122 | *saveptr = str; 123 | token = *saveptr; 124 | 125 | if (!token) 126 | return NULL; 127 | 128 | token += _strspn(token, delim); 129 | *saveptr = _strpbrk(token, delim); 130 | if (*saveptr) 131 | *(*saveptr)++ = '\0'; 132 | 133 | return *token ? token : NULL; 134 | } 135 | 136 | 137 | int _strcasecmp(const char *s1, const char *s2) 138 | { 139 | const u_char *cm = charmap; 140 | const u_char *us1 = (const u_char *)s1; 141 | const u_char *us2 = (const u_char *)s2; 142 | 143 | while (cm[*us1] == cm[*us2++]) 144 | if (*us1++ == '\0') 145 | return (0); 146 | return (cm[*us1] - cm[*--us2]); 147 | } 148 | 149 | /* 150 | * sizeof(word) MUST BE A POWER OF TWO 151 | * SO THAT wmask BELOW IS ALL ONES 152 | */ 153 | typedef long word; /* "word" used for optimal copy speed */ 154 | 155 | #define wsize sizeof(word) 156 | #define wmask (wsize - 1) 157 | 158 | #define MEMCOPY 159 | /* 160 | * Copy a block of memory, handling overlap. 161 | * This is the routine that actually implements 162 | * (the portable versions of) bcopy, memcpy, and memmove. 163 | */ 164 | #ifdef MEMCOPY 165 | void * 166 | memcpy(void *dst0, const void *src0, size_t length) 167 | #else 168 | #ifdef MEMMOVE 169 | void * 170 | memmove(void *dst0, const void *src0, size_t length) 171 | #else 172 | void 173 | bcopy(const void *src0, void *dst0, size_t length) 174 | #endif 175 | #endif 176 | { 177 | char *dst = dst0; 178 | const char *src = src0; 179 | size_t t; 180 | 181 | if (length == 0 || dst == src) /* nothing to do */ 182 | goto done; 183 | 184 | /* 185 | * Macros: loop-t-times; and loop-t-times, t>0 186 | */ 187 | #define TLOOP(s) if (t) TLOOP1(s) 188 | #define TLOOP1(s) do { s; } while (--t) 189 | 190 | if ((unsigned long)dst < (unsigned long)src) { 191 | /* 192 | * Copy forward. 193 | */ 194 | t = (long)src; /* only need low bits */ 195 | if ((t | (long)dst) & wmask) { 196 | /* 197 | * Try to align operands. This cannot be done 198 | * unless the low bits match. 199 | */ 200 | if ((t ^ (long)dst) & wmask || length < wsize) 201 | t = length; 202 | else 203 | t = wsize - (t & wmask); 204 | length -= t; 205 | TLOOP1(*dst++ = *src++); 206 | } 207 | /* 208 | * Copy whole words, then mop up any trailing bytes. 209 | */ 210 | t = length / wsize; 211 | TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize); 212 | t = length & wmask; 213 | TLOOP(*dst++ = *src++); 214 | } else { 215 | /* 216 | * Copy backwards. Otherwise essentially the same. 217 | * Alignment works as before, except that it takes 218 | * (t&wmask) bytes to align, not wsize-(t&wmask). 219 | */ 220 | src += length; 221 | dst += length; 222 | t = (long)src; 223 | if ((t | (long)dst) & wmask) { 224 | if ((t ^ (long)dst) & wmask || length <= wsize) 225 | t = length; 226 | else 227 | t &= wmask; 228 | length -= t; 229 | TLOOP1(*--dst = *--src); 230 | } 231 | t = length / wsize; 232 | TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src); 233 | t = length & wmask; 234 | TLOOP(*--dst = *--src); 235 | } 236 | done: 237 | #if defined(MEMCOPY) || defined(MEMMOVE) 238 | return (dst0); 239 | #else 240 | return; 241 | #endif 242 | } 243 | 244 | int _isspace(char c) 245 | { 246 | return (c == ' ' 247 | || c == '\f' 248 | || c == '\n' 249 | || c == '\r' 250 | || c == '\t' 251 | || c == '\v'); 252 | } 253 | 254 | int _isdigit(char c) 255 | { 256 | return (c >= '0' && c <= '9'); 257 | } 258 | 259 | int _isxdigit(char c) 260 | { 261 | return ((c >= '0' && c <= '9') || 262 | (c >= 'a' && c <= 'f') || 263 | (c >= 'A' && c <= 'F')); 264 | } 265 | 266 | int _isupper(char c) 267 | { 268 | return (c >= 'A' && c <= 'Z'); 269 | } 270 | 271 | int _islower(char c) 272 | { 273 | return (c >= 'a' && c <= 'z'); 274 | } 275 | 276 | int _isalpha(char c) 277 | { 278 | return _isupper(c) || _islower(c); 279 | } 280 | 281 | int _isalnum(char c) 282 | { 283 | return _isalpha(c) || _isdigit(c); 284 | } 285 | 286 | int _toupper(char c) 287 | { 288 | if (!_islower(c)) 289 | return c; 290 | return c - ('a' - 'A'); 291 | } 292 | 293 | void *memset (void *dst0, int val, size_t length) 294 | { 295 | uint8_t *ptr = dst0; 296 | while(length--) 297 | *ptr++ = val; 298 | return dst0; 299 | } 300 | 301 | void __aeabi_memset(void *dst0, char val, size_t length) 302 | { 303 | memset(dst0, val, length); 304 | } 305 | 306 | void *__aeabi_memcpy(void *dst0, void *src, size_t length) 307 | { 308 | return memcpy(dst0, src, length); 309 | } 310 | 311 | int _strlen(const char *s) 312 | { 313 | int i = 0; 314 | while(s[i++]); 315 | return i; 316 | } 317 | 318 | int _strnlen(const char *s, uint32_t maxlen) 319 | { 320 | int i = 0; 321 | while(s[i++] && i < maxlen); 322 | return i; 323 | } 324 | 325 | void _usleep(uint32_t usecs) 326 | { 327 | uint32_t i, j; 328 | for (i = 0; i < usecs; i++) { 329 | for (j = 0; j < 73; j++) { 330 | asm("nop"); 331 | } 332 | } 333 | } 334 | 335 | void _msleep(uint32_t msecs) 336 | { 337 | uint32_t i, j; 338 | for (i = 0; i < msecs; i++) { 339 | for (j = 0; j < 73000; j++) { 340 | asm("nop"); 341 | } 342 | } 343 | } 344 | 345 | int puts(const char *str) 346 | { 347 | serial_puts(str); 348 | serial_putc('\r'); 349 | serial_putc('\n'); 350 | return 1; 351 | } 352 | 353 | int putchar(int c) 354 | { 355 | if (c == '\n') 356 | serial_putc('\r'); 357 | serial_putc(c); 358 | return c; 359 | } 360 | -------------------------------------------------------------------------------- /cmd-bl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "memio.h" 4 | #include "printf.h" 5 | #include "serial.h" 6 | #include "fernvale-bl.h" 7 | 8 | int cmd_bl(int argc, char **argv) 9 | { 10 | uint32_t level; 11 | int i; 12 | 13 | if (argc < 1) { 14 | printf("Usage: bl [level 0-%d]\n", BLLED_MAX_LEVEL); 15 | return -1; 16 | } 17 | 18 | level = strtoul(argv[0], NULL, 0); 19 | 20 | if( level > BLLED_MAX_LEVEL ) { 21 | level = 0; 22 | printf( "Backlight level should be 0-5\n" ); 23 | } 24 | 25 | if( level > 0 ) { 26 | for( i = 0; i < BLLED_BANKS; i++ ) { 27 | *((volatile uint32_t *) BLLED_REG0_BANK(i)) = 28 | ((level << BLLED_REG0_STEP_BIT) & BLLED_REG0_STEP_MSK) | 29 | ((1 << BLLED_REG0_MODE_BIT) | (1 << BLLED_REG0_EN_BIT)); 30 | } 31 | 32 | } else { 33 | for( i = 0; i < BLLED_BANKS; i++ ) { 34 | *((volatile uint32_t *) BLLED_REG0_BANK(i)) = 0; // meh 35 | } 36 | } 37 | 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /cmd-hex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "memio.h" 4 | #include "printf.h" 5 | #include "serial.h" 6 | #include "utils.h" 7 | 8 | int cmd_hex(int argc, char **argv) 9 | { 10 | uint32_t offset; 11 | int count = 0x200; 12 | if (argc < 1) { 13 | printf("Usage: hex [offset] [[count]]\n"); 14 | return -1; 15 | } 16 | 17 | offset = strtoul(argv[0], NULL, 0); 18 | 19 | if (argc > 1) 20 | count = strtoul(argv[1], NULL, 0); 21 | 22 | serial_print_hex((const void *)offset, count); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /cmd-irq.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "bionic.h" 4 | #include "irq.h" 5 | #include "printf.h" 6 | 7 | static void print_help(void) 8 | { 9 | printf("Usage:\n"); 10 | printf("irq sim [num] Simulate IRQ [num]\n"); 11 | printf("irq enable [num] Enable IRQ [num]\n"); 12 | printf("irq disable [num] Disable IRQ [num]\n"); 13 | } 14 | 15 | int cmd_irq(int argc, char **argv) 16 | { 17 | int num; 18 | 19 | if (argc != 2) { 20 | print_help(); 21 | return -1; 22 | } 23 | 24 | num = strtoul(argv[1], NULL, 0); 25 | if (num >= __irq_max__) { 26 | printf("Only %d IRQs present\n", __irq_max__); 27 | return -1; 28 | } 29 | 30 | if (!_strcasecmp(argv[0], "sim")) { 31 | printf("Simulating IRQ %d\n", num); 32 | irq_stimulate(num); 33 | } 34 | 35 | else if (!_strcasecmp(argv[0], "enable")) { 36 | printf("Enabling IRQ %d\n", num); 37 | irq_enable(num); 38 | } 39 | 40 | else if (!_strcasecmp(argv[0], "disable")) { 41 | printf("Disabling IRQ %d\n", num); 42 | irq_disable(num); 43 | } 44 | 45 | else { 46 | printf("Unknown command\n"); 47 | print_help(); 48 | return -1; 49 | } 50 | 51 | return 0; 52 | } 53 | 54 | int cmd_swi(int argc, char **argv) 55 | { 56 | printf("Generating SWI...\n"); 57 | asm volatile ("swi #0\n"); 58 | printf("Returned from SWI\n"); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /cmd-keypad.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "memio.h" 4 | #include "printf.h" 5 | #include "serial.h" 6 | 7 | #include "fernvale-kbd.h" 8 | 9 | #ifndef ARRAY_SIZE 10 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) 11 | #endif 12 | 13 | const char key_vals[] = "LRUDAB123456789*0#"; 14 | 15 | const uint32_t key_addr[] = { 16 | KBD_MEM2, 17 | KBD_MEM2, 18 | KBD_MEM1, 19 | KBD_MEM1, 20 | KBD_MEM3, 21 | KBD_MEM3, 22 | KBD_MEM2, 23 | KBD_MEM1, 24 | KBD_MEM3, 25 | KBD_MEM2, 26 | KBD_MEM1, 27 | KBD_MEM3, 28 | KBD_MEM2, 29 | KBD_MEM1, 30 | KBD_MEM3, 31 | KBD_MEM2, 32 | KBD_MEM2, 33 | KBD_MEM2, 34 | }; 35 | 36 | const uint32_t key_mask[] = { 37 | 0x0000fffb, 38 | 0x0000fff7, 39 | 0x0000fdff, 40 | 0x0000fbff, 41 | 0x0000ffef, 42 | 0x0000ffdf, 43 | 0x0000ffef, 44 | 0x0000f7ff, 45 | 0x0000ffbf, 46 | 0x0000ffdf, 47 | 0x0000efff, 48 | 0x0000ff7f, 49 | 0x0000ffbf, 50 | 0x0000dfff, 51 | 0x0000feff, 52 | 0x0000dfff, 53 | 0x0000bfff, 54 | 0x00007fff, 55 | }; 56 | 57 | int cmd_keypad(int argc, char **argv) 58 | { 59 | int end = 0; 60 | uint32_t key_state[18] = {0}; 61 | 62 | printf("Press %c on keypad or any key on serial to exit\n", 63 | key_vals[ARRAY_SIZE(key_vals) - 2]); 64 | 65 | while (!end && !serial_available()) { 66 | int key; 67 | 68 | for (key = 0; key < (ARRAY_SIZE(key_vals) - 1); key++) { 69 | int v = readl(key_addr[key]); 70 | int newstate = (v == key_mask[key]); 71 | 72 | if (newstate && !key_state[key]) { 73 | serial_putc(key_vals[key]); 74 | if (key == (ARRAY_SIZE(key_vals) - 2)) 75 | end = 1; 76 | if (argc) 77 | end = 1; 78 | } 79 | key_state[key] = newstate; 80 | } 81 | } 82 | 83 | printf("\n"); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /cmd-lcd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "memio.h" 4 | #include "printf.h" 5 | #include "fernvale-lcd.h" 6 | #include "lcd.h" 7 | 8 | #ifdef LCD_DEBUG 9 | static void lcd_dump(void) 10 | { 11 | /* Dump registers */ 12 | // printf("LCD_PAR0_CMD_PORT: %04x\n", readw(LCD_PAR0_CMD_PORT_REG)); 13 | // printf("LCD_PAR0_DAT_PORT: %04x\n", readw(LCD_PAR0_DAT_PORT_REG)); 14 | // printf("LCD_PAR1_CMD_PORT: %04x\n", readw(LCD_PAR1_CMD_PORT_REG)); 15 | // printf("LCD_PAR1_DAT_PORT: %04x\n", readw(LCD_PAR1_DAT_PORT_REG)); 16 | // printf("LCD_PAR0_CFG: %08x\n", readl(LCD_PAR0_CFG_REG)); 17 | // printf("LCD_PAR1_CFG: %08x\n", readl(LCD_PAR1_CFG_REG)); 18 | printf("LCD_STATUS: %04x\n", readw(LCD_STATUS_REG)); 19 | printf("LCD_INT_ENA: %04x\n", readw(LCD_INT_ENA_REG)); 20 | printf("LCD_INT_STAT: %04x\n", readw(LCD_INT_STAT_REG)); 21 | printf("LCD_RUN: %04x\n", readw(LCD_RUN_REG)); 22 | printf("LCD_RESET: %04x\n", readw(LCD_RESET_REG)); 23 | printf("LCD_PAR_DATA_WIDTH: %08x\n", readl(LCD_PAR_DATA_WIDTH_REG)); 24 | printf("LCD_TEARING: %08x\n", readl(LCD_TEARING_REG)); 25 | printf("LCD_AUTOCOPY_CTRL: %08x\n", readl(LCD_AUTOCOPY_CTRL_REG)); 26 | printf("LCD_AUTOCOPY_OFFSET: %08x\n", readl(LCD_AUTOCOPY_OFFSET_REG)); 27 | printf("LCD_AUTOCOPY_SIZE: %08x\n", readl(LCD_AUTOCOPY_SIZE_REG)); 28 | printf("LCD_AUTOCOPY_CMD_ADDR: %04x\n", readw(LCD_AUTOCOPY_CMD_ADDR_REG)); 29 | printf("LCD_AUTOCOPY_DATA_ADDR: %04x\n", readw(LCD_AUTOCOPY_DATA_ADDR_REG)); 30 | printf("LCD_LAYER0_CTRL: %08x\n", readl(LCD_LAYER0_CTRL_REG)); 31 | printf("LCD_LAYER0_OFFSET: %08x\n", readl(LCD_LAYER0_OFFSET_REG)); 32 | printf("LCD_LAYER0_SIZE: %08x\n", readl(LCD_LAYER0_SIZE_REG)); 33 | printf("LCD_LAYER0_SRC_ADDR: %08x\n", readl(LCD_LAYER0_SRC_ADDR_REG)); 34 | // printf("LCD_LAYER0_MEM_PITCH: %08x\n", readl(LCD_LAYER0_MEM_PITCH_REG)); 35 | // printf("LCD_FRAME_COUNTER_CON: %08x\n", readl(LCD_FRAME_COUNTER_CON_REG)); 36 | // printf("LCD_FRAME_COUNTER: %08x\n", readl(LCD_FRAME_COUNTER_REG)); 37 | } 38 | #endif /* LCD_DEBUG */ 39 | 40 | static int is_command(int argc, char **argv, const char *cmd) 41 | { 42 | return ((argc > 0) && !_strcasecmp(argv[0], cmd)); 43 | } 44 | 45 | static pixel_t color_wheel(int step) { 46 | step &= 255; 47 | if (step < 85) { 48 | return rgb(step * 3, 255 - step * 3, 0); 49 | } 50 | else if (step < 170) { 51 | step -= 85; 52 | return rgb(255 - step * 3, 0, step * 3); 53 | } 54 | else { 55 | step -= 170; 56 | return rgb(0, step * 3, 255 - step * 3); 57 | } 58 | } 59 | 60 | int cmd_lcd(int argc, char **argv) 61 | { 62 | int i; 63 | int ret; 64 | 65 | if (is_command(argc, argv, "init")) { 66 | printf("Initializing LCD... "); 67 | ret = lcd_init(); 68 | if (ret) 69 | printf("failed: %d\n", ret); 70 | else 71 | printf("Ok\n"); 72 | } 73 | #ifdef LCD_DEBUG 74 | else if (is_command(argc, argv, "dump")) { 75 | lcd_dump(); 76 | } 77 | #endif 78 | else if (is_command(argc, argv, "run")) { 79 | printf("Running LCD... "); 80 | ret = lcd_run(); 81 | if (ret) 82 | printf("failed: %d\n", ret); 83 | else 84 | printf("Ok\n"); 85 | } 86 | else if (is_command(argc, argv, "stop")) { 87 | printf("Stopping LCD... "); 88 | ret = lcd_stop(); 89 | if (ret) 90 | printf("failed: %d\n", ret); 91 | else 92 | printf("Ok\n"); 93 | } 94 | else if (is_command(argc, argv, "tpp1")) { 95 | int w = lcd_width(); 96 | int h = lcd_height(); 97 | int total = w * h; 98 | 99 | for (i = 0; i < total; i++) 100 | lcd_addpixel(i); 101 | } 102 | else if (is_command(argc, argv, "tpp2")) { 103 | int x, y; 104 | 105 | i = 0; 106 | for (y = 0; y < lcd_height(); y++) 107 | for (x = 0; x < lcd_width(); x++) 108 | lcd_addpixel(rgb(i++, 0, 0)); 109 | } 110 | else if (is_command(argc, argv, "tpd")) { 111 | static int step = 0; 112 | pixel_t *fb; 113 | int x, y; 114 | int w, h; 115 | 116 | fb = lcd_fb(); 117 | 118 | h = lcd_height(); 119 | w = lcd_width(); 120 | 121 | /* Stupid clear-screen */ 122 | memset(fb, 0, w * h * lcd_bpp()); 123 | 124 | printf("Width: %d Height: %d\n", w, h); 125 | 126 | i = step++; 127 | fb = lcd_fb(); 128 | for (y = 0; y < h; y++) { 129 | for (x = 0; x < w; x++) { 130 | /* Swap axes, to verify X and Y work */ 131 | if (step & 1) 132 | *fb++ = color_wheel(y + step); 133 | else 134 | *fb++ = color_wheel(x + step); 135 | } 136 | } 137 | lcd_run(); 138 | } 139 | else { 140 | printf("lcd sub-commands (usage: lcd [subcmd]):\n"); 141 | printf("\tinit Initialize LCD registers\n"); 142 | printf("\trun Transfer one frame of the LCD\n"); 143 | printf("\tstop Stop and reset LCD auto-update\n"); 144 | #ifdef LCD_DEBUG 145 | printf("\tdump Dump current register list\n"); 146 | #endif 147 | printf("\ttpp1 Display bitbanged, PIO 'test pattern 1'\n"); 148 | printf("\ttpp2 Display bitbanged, PIO 'test pattern 2'\n"); 149 | printf("\ttpd DMA test pattern (flips on each iteration)\n"); 150 | } 151 | 152 | return 0; 153 | } 154 | 155 | -------------------------------------------------------------------------------- /cmd-led.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "memio.h" 4 | #include "printf.h" 5 | #include "serial.h" 6 | #include "fernvale-kbd.h" 7 | 8 | int cmd_led(int argc, char **argv) 9 | { 10 | uint32_t state; 11 | 12 | if (argc < 1) { 13 | printf("Usage: led [1 = on, 0 = off]\n"); 14 | return -1; 15 | } 16 | 17 | state = strtoul(argv[0], NULL, 0); 18 | 19 | if( state ) { 20 | *((volatile uint32_t *) BIG_LED_ADDR) = BIG_LED_ON; 21 | } else { 22 | *((volatile uint32_t *) BIG_LED_ADDR) = BIG_LED_OFF; 23 | } 24 | 25 | return 0; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /cmd-load.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "serial.h" 4 | #include "printf.h" 5 | #include "memio.h" 6 | 7 | int cmd_load(int argc, char **argv) 8 | { 9 | uint32_t offset; 10 | uint32_t total; 11 | uint32_t left; 12 | 13 | if (argc != 2) { 14 | printf("Usage: load [offset] [size]\n" 15 | "Loads [size] bytes to address [offset]\n"); 16 | return 1; 17 | } 18 | 19 | offset = strtoul(argv[0], NULL, 0); 20 | total = strtoul(argv[1], NULL, 0); 21 | 22 | left = total; 23 | while (left--) 24 | writeb(serial_getc(), offset++); 25 | 26 | return 0; 27 | } 28 | 29 | int cmd_loadjump(int argc, char **argv) 30 | { 31 | uint32_t offset; 32 | uint32_t total; 33 | uint32_t left; 34 | 35 | void (*jumpaddr)(void); 36 | 37 | if (argc != 2) { 38 | printf("Usage: loadjmp [offset] [size]\n" 39 | "Loads [size] bytes to address [offset], and " 40 | "jumps to [offset] afterwards.\n"); 41 | return 1; 42 | } 43 | 44 | offset = strtoul(argv[0], NULL, 0); 45 | total = strtoul(argv[1], NULL, 0); 46 | jumpaddr = (void (*)(void))offset; 47 | 48 | left = total; 49 | 50 | while (left--) 51 | writeb(serial_getc(), offset++); 52 | 53 | jumpaddr(); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /cmd-peekpoke.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "bionic.h" 4 | #include "memio.h" 5 | #include "printf.h" 6 | #include "serial.h" 7 | 8 | int cmd_peek(int argc, char **argv) 9 | { 10 | uint32_t offset; 11 | 12 | if (argc < 1) { 13 | printf("Usage: peek [offset]\n"); 14 | return -1; 15 | } 16 | 17 | offset = strtoul(argv[0], NULL, 0); 18 | 19 | printf("Value at 0x%08"PRIx32": ", offset); 20 | printf("0x%08"PRIx32"\n", *((volatile uint32_t *)offset)); 21 | return 0; 22 | } 23 | 24 | int cmd_poke(int argc, char **argv) 25 | { 26 | uint32_t offset; 27 | uint32_t val; 28 | 29 | if (argc < 2) { 30 | printf("Usage: poke [offset] [val]\n"); 31 | return -1; 32 | } 33 | 34 | offset = strtoul(argv[0], NULL, 0); 35 | val = strtoul(argv[1], NULL, 0); 36 | 37 | printf("Setting value at 0x%08"PRIx32" to 0x%08"PRIx32": ", 38 | offset, val); 39 | writel(val, offset); 40 | printf("Ok\n"); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /cmd-reboot.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memio.h" 3 | #include "printf.h" 4 | 5 | static int wdt_reboot(void) 6 | { 7 | writel(0x1209, 0xa003001c); 8 | return 0; 9 | } 10 | 11 | int cmd_reboot(int argc, char **argv) 12 | { 13 | printf("Rebooting...\n"); 14 | wdt_reboot(); 15 | while(1); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /cmd-sleep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "printf.h" 4 | 5 | int cmd_msleep(int argc, char **argv) 6 | { 7 | uint32_t msecs; 8 | 9 | if (argc != 1) { 10 | printf("Usage: msleep [milliseconds]\n"); 11 | return 1; 12 | } 13 | 14 | msecs = strtoul(argv[0], NULL, 0); 15 | _msleep(msecs); 16 | return 0; 17 | } 18 | 19 | int cmd_usleep(int argc, char **argv) 20 | { 21 | uint32_t usecs; 22 | 23 | if (argc != 1) { 24 | printf("Usage: usleep [microseconds]\n"); 25 | return 1; 26 | } 27 | 28 | usecs = strtoul(argv[0], NULL, 0); 29 | _usleep(usecs); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /cmd-spi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "serial.h" 4 | #include "printf.h" 5 | #include "spi.h" 6 | 7 | static int do_flashrom(void) 8 | { 9 | uint8_t out_count; 10 | uint8_t in_count; 11 | uint8_t out[256]; 12 | uint8_t in[256]; 13 | 14 | serial_putc(0x05); 15 | 16 | while (1) { 17 | out_count = serial_getc(); 18 | in_count = serial_getc(); 19 | 20 | if ((!in_count) && (!out_count)) 21 | return 0; 22 | 23 | serial_read(out, out_count); 24 | spi_cmd_txrx(out_count, in_count, out, in); 25 | serial_write(in, in_count); 26 | } 27 | } 28 | 29 | int cmd_spi(int argc, char **argv) 30 | { 31 | uint32_t recv_bytes_count; 32 | uint8_t xmit_bytes[argc - 1]; 33 | int i; 34 | 35 | if (argc > 0 && !_strcasecmp(argv[0], "id")) { 36 | uint8_t out[1] = {0x9f}; 37 | uint8_t in[3]; 38 | 39 | spi_cmd_txrx(sizeof(out), sizeof(in), out, in); 40 | 41 | printf("ID: %02x %02x %02x\n", in[0], in[1], in[2]); 42 | 43 | return 0; 44 | } 45 | 46 | if (argc > 0 && !_strcasecmp(argv[0], "flashrom")) 47 | return do_flashrom(); 48 | 49 | if (argc < 2) { 50 | printf("Send SPI bytes out and read the response.\n"); 51 | printf("Usage:\n"); 52 | printf(" spi [count] [byte 1] [byte 2] ...\n"); 53 | printf(" Where \"count\" is the number of bytes to expect" 54 | " in response.\n"); 55 | printf(" spi id get device id\n"); 56 | printf(" spi flashrom enter 'flashrom' prog mode\n"); 57 | return 1; 58 | } 59 | 60 | recv_bytes_count = strtoul(argv[0], NULL, 0); 61 | uint8_t recv_bytes[recv_bytes_count]; 62 | 63 | for (i = 1; i < argc; i++) 64 | xmit_bytes[i - 1] = strtoul(argv[i], NULL, 0); 65 | 66 | printf("Transmitting %d bytes and expecting a response with %d bytes:\n", 67 | sizeof(xmit_bytes), sizeof(recv_bytes)); 68 | serial_print_hex(xmit_bytes, sizeof(xmit_bytes)); 69 | 70 | spi_cmd_txrx(sizeof(xmit_bytes), sizeof(recv_bytes), 71 | xmit_bytes, recv_bytes); 72 | 73 | printf("Response:\n"); 74 | serial_print_hex(recv_bytes, sizeof(recv_bytes)); 75 | 76 | return 0; 77 | } 78 | 79 | int cmd_spi_raw(int argc, char **argv) 80 | { 81 | uint32_t recv_bytes_count; 82 | uint8_t xmit_bytes[argc - 1]; 83 | int i; 84 | 85 | if (argc < 2) { 86 | printf("Quietly send SPI bytes out and read the response.\n"); 87 | printf("Usage:\n"); 88 | printf(" spi_raw [count] [byte 1] [byte 2] ...\n"); 89 | printf(" Where \"count\" is the number of bytes to expect" 90 | " in response.\n"); 91 | return 1; 92 | } 93 | 94 | recv_bytes_count = strtoul(argv[0], NULL, 0); 95 | uint8_t recv_bytes[recv_bytes_count]; 96 | 97 | for (i = 1; i < argc; i++) 98 | xmit_bytes[i - 1] = strtoul(argv[i], NULL, 16); 99 | 100 | spi_cmd_txrx(sizeof(xmit_bytes), sizeof(recv_bytes), 101 | xmit_bytes, recv_bytes); 102 | 103 | for (i = 0; i < recv_bytes_count; i++) { 104 | serial_puth(recv_bytes[i], 2); 105 | serial_puts(" "); 106 | } 107 | 108 | serial_puts("\n"); 109 | 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /emi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "memio.h" 4 | 5 | #include "fernvale-emi.h" 6 | #include "fernvale-pmic.h" 7 | 8 | #define PSRAM_TEST_SHOULD_INVERT (1 << 0) 9 | #define PSRAM_TEST_SHOULD_RANDOMIZE (1 << 1) 10 | 11 | /* Use the built-in memory self test to check calibration */ 12 | static int psram_test_run(uint32_t addr, uint32_t length, uint16_t pattern) 13 | { 14 | int run; 15 | uint32_t test_range; 16 | uint32_t params; 17 | int tries; 18 | 19 | test_range = (addr << 8) & 0xffff0000; 20 | test_range |= (length >> 8) - 1; 21 | 22 | for (run = 0; run < 4; run++) { 23 | /* Params contains the "start key", plus some other flags */ 24 | params = EMI_CTRL_MBISTB_START_KEY; 25 | 26 | /* On some runs, invert the pattern */ 27 | if (run & PSRAM_TEST_SHOULD_INVERT) 28 | params |= EMI_CTRL_MBISTB_INVERT; 29 | 30 | /* On some runs, randomize the data */ 31 | if (run & PSRAM_TEST_SHOULD_RANDOMIZE) 32 | params |= EMI_CTRL_MBISTB_RANDOMIZE; 33 | 34 | /* Reset MBIST engine */ 35 | writel(0, EMI_CTRL_MBISTA); 36 | 37 | /* Set range (start and length) */ 38 | writel(test_range, EMI_CTRL_MBISTB); 39 | 40 | /* Kick off the test */ 41 | writel(params, EMI_CTRL_MBISTA); 42 | 43 | /* Wait for it to finish */ 44 | for (tries = 0; tries < 256; tries++) 45 | if (readl(EMI_CTRL_MBISTD) & EMI_CTRL_MBISTD_FINISHED) 46 | break; 47 | 48 | /* If it didn't finish, try again */ 49 | if (!(readl(EMI_CTRL_MBISTD) & EMI_CTRL_MBISTD_FINISHED)) 50 | continue; 51 | 52 | /* If the test failed, return false */ 53 | if ( readl(EMI_CTRL_MBISTD) & EMI_CTRL_MBISTD_FAILURE ) 54 | return 0; 55 | } 56 | 57 | return 1; 58 | } 59 | 60 | static int psram_test(void) 61 | { 62 | int i; 63 | uint32_t test_start = 0x100000; 64 | uint32_t test_length = 0x8000; 65 | 66 | uint16_t patterns[] = {0xffff, 0xa55a}; 67 | 68 | 69 | for (i = 0; i < sizeof(patterns)/sizeof(*patterns); i++) 70 | if (!psram_test_run(test_start, test_length, patterns[i])) 71 | return 0; 72 | 73 | /* All tests passed */ 74 | return 1; 75 | } 76 | 77 | /* Set all 16 DQY delays to the same value */ 78 | static void psram_set_ganged_dqy(uint8_t delay) 79 | { 80 | uint32_t vals = (delay << 0) | 81 | (delay << 8) | 82 | (delay << 16) | 83 | (delay << 24); 84 | writel(vals, EMI_CTRL_IDLA); 85 | writel(vals, EMI_CTRL_IDLB); 86 | writel(vals, EMI_CTRL_IDLC); 87 | writel(vals, EMI_CTRL_IDLD); 88 | } 89 | 90 | static void psram_set_ganged_dqs(uint8_t delay) 91 | { 92 | uint32_t vals = (delay << 24) | 93 | (delay << 16); 94 | writel(vals, EMI_CTRL_IDLE); 95 | } 96 | 97 | int dqy_delay; 98 | int dqy_delay_upper; 99 | int dqy_delay_lower; 100 | 101 | int dqs_delay; 102 | int dqs_delay_upper; 103 | int dqs_delay_lower; 104 | 105 | int calibrate_psram(void) 106 | { 107 | dqy_delay = -1; 108 | dqy_delay_upper = -1; 109 | dqy_delay_lower = -1; 110 | 111 | dqs_delay = -1; 112 | dqs_delay_upper = -1; 113 | dqs_delay_lower = -1; 114 | 115 | for (dqy_delay = 0; dqy_delay < 32; dqy_delay++) { 116 | 117 | /* 118 | * Since this chip is probably routed properly, assume 119 | * all trace lengths require the same delay. 120 | */ 121 | psram_set_ganged_dqy(dqy_delay); 122 | if (psram_test()) { 123 | if (dqy_delay_lower == -1) 124 | dqy_delay_lower = dqy_delay; 125 | else 126 | dqy_delay_upper = dqy_delay; 127 | } 128 | } 129 | 130 | if (-1 == dqy_delay_upper) 131 | dqy_delay_upper = dqy_delay_lower; 132 | 133 | if (dqy_delay_upper != -1) { 134 | dqy_delay = (dqy_delay_lower + dqy_delay_upper) / 2; 135 | psram_set_ganged_dqy(dqy_delay); 136 | return 1; 137 | } 138 | 139 | /* If DQY delays fail, try DQS instead */ 140 | psram_set_ganged_dqy(0); 141 | for (dqs_delay = 1; dqs_delay <= 31; dqs_delay++) { 142 | psram_set_ganged_dqs(dqs_delay); 143 | if (psram_test()) { 144 | if (dqs_delay_lower == -1) 145 | dqs_delay_lower = dqs_delay; 146 | else 147 | dqs_delay_upper = dqs_delay; 148 | return 1; 149 | } 150 | } 151 | 152 | if (-1 == dqs_delay_lower) 153 | dqs_delay = -1; 154 | 155 | if (-1 == dqs_delay_upper) 156 | dqs_delay_upper = dqs_delay_lower; 157 | 158 | if (dqs_delay_upper != -1) { 159 | dqs_delay = (dqs_delay_upper + dqs_delay_lower) / 2; 160 | psram_set_ganged_dqs(dqs_delay); 161 | return 1; 162 | } 163 | 164 | /* Failure */ 165 | return 0; 166 | } 167 | -------------------------------------------------------------------------------- /fernvale.ld: -------------------------------------------------------------------------------- 1 | /************************************************************ 2 | * configs/c5471evm/scripts/ld.script 3 | * 4 | * Copyright (C) 2007, 2011-2012, 2014 Gregory Nutt. All rights reserved. 5 | * Author: Gregory Nutt 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in 15 | * the documentation and/or other materials provided with the 16 | * distribution. 17 | * 3. Neither the name Gregory Nutt nor the names of its contributors may be 18 | * used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | * 34 | ************************************************************/ 35 | 36 | OUTPUT_ARCH(arm) 37 | ENTRY(_stext) 38 | SECTIONS 39 | { 40 | /* The OS entry point is here */ 41 | 42 | . = 0x70006000; /* bootloader will copy data to this address */ 43 | .text : { 44 | _stext = ABSOLUTE(.); 45 | KEEP(*(vectors)) 46 | *(.text) 47 | *(.fixup) 48 | *(.gnu.warning) 49 | *(.rodata) 50 | *(.glue_7) 51 | *(.glue_7t) 52 | *(.got) /* Global offset table */ 53 | _etext = ABSOLUTE(.); 54 | } 55 | 56 | _eronly = ABSOLUTE(.); /* See below */ 57 | . = ALIGN(4096); 58 | 59 | .data : { 60 | _sdata = ABSOLUTE(.); 61 | *(.data) 62 | CONSTRUCTORS 63 | _edata = ABSOLUTE(.); 64 | } 65 | 66 | .bss : { /* BSS */ 67 | _sbss = ABSOLUTE(.); 68 | *(.bss) 69 | *(COMMON) 70 | _ebss = ABSOLUTE(.); 71 | } 72 | /* Stabs debugging sections. */ 73 | .stab 0 : { *(.stab) } 74 | .stabstr 0 : { *(.stabstr) } 75 | .stab.excl 0 : { *(.stab.excl) } 76 | .stab.exclstr 0 : { *(.stab.exclstr) } 77 | .stab.index 0 : { *(.stab.index) } 78 | .stab.indexstr 0 : { *(.stab.indexstr) } 79 | .comment 0 : { *(.comment) } 80 | .debug_abbrev 0 : { *(.debug_abbrev) } 81 | .debug_info 0 : { *(.debug_info) } 82 | .debug_line 0 : { *(.debug_line) } 83 | .debug_pubnames 0 : { *(.debug_pubnames) } 84 | .debug_aranges 0 : { *(.debug_aranges) } 85 | } 86 | -------------------------------------------------------------------------------- /flashrom-fernvale.patch: -------------------------------------------------------------------------------- 1 | This patch adds "fernvale_spi" "programmer" for "flashrom" utility 2 | http://flashrom.org/ . It allows read or program FlashROM on a 3 | Mediatek MT6260 device using "fernly" bootloader 4 | https://github.com/xobs/fernly . 5 | 6 | Author: Sean Cross 7 | 8 | Index: Makefile 9 | =================================================================== 10 | --- Makefile (revision 1897) 11 | +++ Makefile (working copy) 12 | @@ -272,6 +272,11 @@ 13 | else 14 | override CONFIG_BUSPIRATE_SPI = no 15 | endif 16 | +ifeq ($(CONFIG_FERNVALE_SPI), yes) 17 | +UNSUPPORTED_FEATURES += CONFIG_FERNVALE_SPI=yes 18 | +else 19 | +override CONFIG_FERNVALE_SPI = no 20 | +endif 21 | ifeq ($(CONFIG_SERPROG), yes) 22 | UNSUPPORTED_FEATURES += CONFIG_SERPROG=yes 23 | else 24 | @@ -469,6 +474,9 @@ 25 | # Always enable Bus Pirate SPI for now. 26 | CONFIG_BUSPIRATE_SPI ?= yes 27 | 28 | +# Always enable Fernvale SPI, too 29 | +CONFIG_FERNVALE_SPI ?= yes 30 | + 31 | # Disable Dediprog SF100 until support is complete and tested. 32 | CONFIG_DEDIPROG ?= no 33 | 34 | @@ -694,6 +702,12 @@ 35 | NEED_SERIAL := yes 36 | endif 37 | 38 | +ifeq ($(CONFIG_FERNVALE_SPI), yes) 39 | +FEATURE_CFLAGS += -D'CONFIG_FERNVALE_SPI=1' 40 | +PROGRAMMER_OBJS += fernvale_spi.o 41 | +NEED_SERIAL := yes 42 | +endif 43 | + 44 | ifeq ($(CONFIG_DEDIPROG), yes) 45 | FEATURE_CFLAGS += -D'CONFIG_DEDIPROG=1' 46 | PROGRAMMER_OBJS += dediprog.o 47 | Index: fernvale_spi.c 48 | =================================================================== 49 | --- fernvale_spi.c (revision 0) 50 | +++ fernvale_spi.c (working copy) 51 | @@ -0,0 +1,238 @@ 52 | +/* 53 | + * This file is part of the flashrom project. 54 | + * 55 | + * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger 56 | + * 57 | + * This program is free software; you can redistribute it and/or modify 58 | + * it under the terms of the GNU General Public License as published by 59 | + * the Free Software Foundation; version 2 of the License. 60 | + * 61 | + * This program is distributed in the hope that it will be useful, 62 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of 63 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 64 | + * GNU General Public License for more details. 65 | + * 66 | + * You should have received a copy of the GNU General Public License 67 | + * along with this program; if not, write to the Free Software 68 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 69 | + */ 70 | + 71 | +#include 72 | +#include 73 | +#include 74 | +#include 75 | +#include 76 | +#include 77 | +#include 78 | +#include 79 | +#include 80 | + 81 | +#include "flash.h" 82 | +#include "programmer.h" 83 | +#include "spi.h" 84 | + 85 | +#define DEFAULT_DEV "/dev/fernvale" 86 | +#define BAUDRATE B921600 87 | + 88 | +static struct { 89 | + int fd; 90 | +} fernvale_data; 91 | + 92 | +static int fernvale_spi_send_command(struct flashctx *flash, 93 | + unsigned int writecnt, unsigned int readcnt, 94 | + const unsigned char *writearr, 95 | + unsigned char *readarr); 96 | + 97 | +static const struct spi_master spi_master_fernvale = { 98 | + .type = SPI_CONTROLLER_FERNVALE, 99 | + .max_data_read = 128, 100 | + .max_data_write = 128, 101 | + .command = fernvale_spi_send_command, 102 | + .multicommand = default_spi_send_multicommand, 103 | + .read = default_spi_read, 104 | + .write_256 = default_spi_write_256, 105 | + .write_aai = default_spi_write_aai, 106 | +}; 107 | + 108 | +static int fernvale_spi_shutdown(void *data) 109 | +{ 110 | + const char cmd[] = { 0, 0 }; 111 | + 112 | + write(fernvale_data.fd, cmd, sizeof(cmd)); 113 | + 114 | + return 0; 115 | +} 116 | + 117 | +static int fernvale_spi_setserial(int serfd) 118 | +{ 119 | + int ret; 120 | + struct termios t; 121 | + 122 | + ret = tcgetattr(serfd, &t); 123 | + if (-1 == ret) { 124 | + perror("Failed to get attributes"); 125 | + exit(1); 126 | + } 127 | + cfsetispeed(&t, BAUDRATE); 128 | + cfsetospeed(&t, BAUDRATE); 129 | + cfmakeraw(&t); 130 | + ret = tcsetattr(serfd, TCSANOW, &t); 131 | + if (-1 == ret) { 132 | + perror("Failed to set attributes"); 133 | + exit(1); 134 | + } 135 | + 136 | + return 0; 137 | +} 138 | + 139 | +int fernvale_spi_init(void) 140 | +{ 141 | + struct spi_master mst = spi_master_fernvale; 142 | + char *dev; 143 | + 144 | + dev = extract_programmer_param("dev"); 145 | + if (dev && !strlen(dev)) { 146 | + free(dev); 147 | + dev = NULL; 148 | + } 149 | + if (!dev) 150 | + dev = DEFAULT_DEV; 151 | + 152 | + fernvale_data.fd = open(dev, O_RDWR); 153 | + if (fernvale_data.fd == -1) { 154 | + msg_perr("Unable to open serial device. " 155 | + "Use flashrom -p fernvale_spi:dev=/dev/ttyUSB0\n"); 156 | + return 1; 157 | + } 158 | + 159 | + fernvale_spi_setserial(fernvale_data.fd); 160 | + 161 | + const char cmd[] = "spi flashrom\n"; 162 | + char readback; 163 | + int ready_tries = 0; 164 | + write(fernvale_data.fd, cmd, strlen(cmd)); 165 | + 166 | + /* Look for "Ready" signal */ 167 | + do { 168 | + read(fernvale_data.fd, &readback, sizeof(readback)); 169 | + ready_tries++; 170 | + } while (readback != 0x05); 171 | + msg_gdbg("Found 'ready' signal after %d bytes\n", ready_tries); 172 | + 173 | + mst.data = &fernvale_data; 174 | + register_spi_master(&mst); 175 | + register_shutdown(fernvale_spi_shutdown, NULL); 176 | + 177 | + return 0; 178 | +} 179 | + 180 | +static int write_full(int fd, const void *bfr, int size) 181 | +{ 182 | + int ret; 183 | + int left = size; 184 | + 185 | + while (left > 0) { 186 | + ret = write(fd, bfr, left); 187 | + if (ret == -1) { 188 | + if (errno == EAGAIN) 189 | + continue; 190 | + return ret; 191 | + } 192 | + 193 | + /* FD closed */ 194 | + if (!ret) 195 | + return -1; 196 | + 197 | + left -= ret; 198 | + bfr += ret; 199 | + } 200 | + return size; 201 | +} 202 | + 203 | +static int read_full(int fd, void *bfr, int size) 204 | +{ 205 | + int ret; 206 | + int left = size; 207 | + 208 | + msg_gdbg(" Reading %d bytes:", size); 209 | + while (left > 0) { 210 | + ret = read(fd, bfr, 1); 211 | + if (ret == -1) { 212 | + if (errno == EAGAIN) 213 | + continue; 214 | + return ret; 215 | + } 216 | + msg_gdbg(" 0x%02x:", *((uint8_t *)bfr)); 217 | + 218 | + /* FD closed */ 219 | + if (!ret) 220 | + return -1; 221 | + 222 | + left -= ret; 223 | + bfr += ret; 224 | + } 225 | + return size; 226 | +} 227 | + 228 | +static int fernvale_spi_send_command(struct flashctx *flash, 229 | + unsigned int writecnt, unsigned int readcnt, 230 | + const unsigned char *writearr, 231 | + unsigned char *readarr) 232 | +{ 233 | + uint8_t out_bytes = writecnt; 234 | + uint8_t in_bytes = readcnt; 235 | + int ret; 236 | + int fd = fernvale_data.fd; 237 | + int i; 238 | +#if 1 239 | + ret = write_full(fd, &out_bytes, sizeof(out_bytes)); 240 | + if (ret != sizeof(out_bytes)) 241 | + msg_perr("0: Wanted to write %d bytes, but got %d\n", 242 | + (int)sizeof(out_bytes), ret); 243 | + 244 | + ret = write_full(fd, &in_bytes, sizeof(in_bytes)); 245 | + if (ret != sizeof(in_bytes)) 246 | + msg_perr("1: Wanted to write %d bytes, but got %d\n", 247 | + (int)sizeof(in_bytes), ret); 248 | + 249 | + ret = write_full(fd, writearr, out_bytes); 250 | + if (ret != out_bytes) 251 | + msg_perr("0: Wanted to write %d bytes, but got %d\n", 252 | + out_bytes, ret); 253 | + 254 | + msg_gdbg(" Wrote %d bytes:", out_bytes); 255 | + for (i = 0; i < out_bytes; i++) 256 | + msg_gdbg(" %02x", writearr[i]); 257 | + msg_gdbg(" "); 258 | +#else 259 | + uint8_t bfr[writecnt + 2]; 260 | + 261 | + bfr[0] = out_bytes; 262 | + bfr[1] = in_bytes; 263 | + memcpy(&bfr[2], writearr, out_bytes); 264 | + 265 | + ret = write_full(fd, bfr, sizeof(bfr)); 266 | + if (ret != sizeof(bfr)) 267 | + msg_perr("0: Wanted to write %d bytes, but got %d\n", 268 | + sizeof(bfr), ret); 269 | + 270 | + msg_gdbg(" Wrote %d bytes:", sizeof(bfr)); 271 | + for (i = 0; i < sizeof(bfr); i++) 272 | + msg_gdbg(" %02x", bfr[i]); 273 | + msg_gdbg(" "); 274 | +#endif 275 | + 276 | + ret = read_full(fd, readarr, in_bytes); 277 | + if (ret != in_bytes) 278 | + msg_perr("3: Wanted to read %d bytes, but got %d\n", 279 | + in_bytes, ret); 280 | + 281 | + msg_gdbg(" Read %d bytes:", in_bytes); 282 | + for (i = 0; i < in_bytes; i++) 283 | + msg_gdbg(" %02x", readarr[i]); 284 | + msg_gdbg(" "); 285 | + 286 | + msg_gdbg("\n"); 287 | + 288 | + return 0; 289 | +} 290 | Index: flashrom.c 291 | =================================================================== 292 | --- flashrom.c (revision 1897) 293 | +++ flashrom.c (working copy) 294 | @@ -231,6 +231,19 @@ 295 | }, 296 | #endif 297 | 298 | +#if CONFIG_FERNVALE_SPI == 1 299 | + { 300 | + .name = "fernvale_spi", 301 | + .type = OTHER, 302 | + /* FIXME */ 303 | + .devs.note = "Kosagi Fernvale\n", 304 | + .init = fernvale_spi_init, 305 | + .map_flash_region = fallback_map, 306 | + .unmap_flash_region = fallback_unmap, 307 | + .delay = internal_delay, 308 | + }, 309 | +#endif 310 | + 311 | #if CONFIG_DEDIPROG == 1 312 | { 313 | .name = "dediprog", 314 | Index: programmer.h 315 | =================================================================== 316 | --- programmer.h (revision 1897) 317 | +++ programmer.h (working copy) 318 | @@ -69,6 +69,9 @@ 319 | #if CONFIG_BUSPIRATE_SPI == 1 320 | PROGRAMMER_BUSPIRATE_SPI, 321 | #endif 322 | +#if CONFIG_FERNVALE_SPI == 1 323 | + PROGRAMMER_FERNVALE_SPI, 324 | +#endif 325 | #if CONFIG_DEDIPROG == 1 326 | PROGRAMMER_DEDIPROG, 327 | #endif 328 | @@ -506,6 +509,11 @@ 329 | int buspirate_spi_init(void); 330 | #endif 331 | 332 | +/* fernvale_spi.c */ 333 | +#if CONFIG_FERNVALE_SPI == 1 334 | +int fernvale_spi_init(void); 335 | +#endif 336 | + 337 | /* linux_spi.c */ 338 | #if CONFIG_LINUX_SPI == 1 339 | int linux_spi_init(void); 340 | @@ -554,6 +562,9 @@ 341 | #if CONFIG_BUSPIRATE_SPI == 1 342 | SPI_CONTROLLER_BUSPIRATE, 343 | #endif 344 | +#if CONFIG_FERNVALE_SPI == 1 345 | + SPI_CONTROLLER_FERNVALE, 346 | +#endif 347 | #if CONFIG_DEDIPROG == 1 348 | SPI_CONTROLLER_DEDIPROG, 349 | #endif 350 | -------------------------------------------------------------------------------- /include/bionic.h: -------------------------------------------------------------------------------- 1 | #ifndef __BIONIC_H__ 2 | #define __BIONIC_H__ 3 | #include 4 | 5 | # define ULONG_MAX 4294967295UL 6 | 7 | size_t _strspn(const char *s1, const char *s2); 8 | char * _strpbrk(const char *s1, const char *s2); 9 | char *_strtok(char *str, const char *delim, char **saveptr); 10 | int _strcasecmp(const char *s1, const char *s2); 11 | void *_memcpy(void *dst0, const void *src0, size_t length); 12 | void *memset(void *__s, int __c, size_t __n); 13 | unsigned long strtoul(const char *nptr, char **endptr, unsigned int base); 14 | int _strlen(const char *s); 15 | int _strnlen(const char *s, uint32_t maxlen); 16 | void _usleep(uint32_t usecs); 17 | void _msleep(uint32_t msecs); 18 | 19 | /* ctype replacements */ 20 | int _isspace(char c); 21 | int _isdigit(char c); 22 | int _isxdigit(char c); 23 | int _isupper(char c); 24 | int _islower(char c); 25 | int _isalpha(char c); 26 | int _isalnum(char c); 27 | int _toupper(char c); 28 | 29 | #endif /* __BIONIC_H__ */ 30 | -------------------------------------------------------------------------------- /include/fernvale-bl.h: -------------------------------------------------------------------------------- 1 | #ifndef __FV_BL_H__ 2 | #define __FV_BL_H__ 3 | 4 | #define BLLED_MAX_LEVEL 5 5 | 6 | #define BLLED_GANG_REG0 (0xA0700000 + 0x0C00) 7 | #define BLLED_GANG_REG2 (0xA0700000 + 0x0C08) 8 | 9 | #define BLLED_BANKS 4 10 | #define BLLED_REG0_BANK(n) (0xA0700000 + 0x0C10 + ((n & 3) << 4)) 11 | #define BLLED_REG1_BANK(n) (0xA0700000 + 0x0C14 + ((n & 3) << 4)) 12 | 13 | /// common across BLLED BANK 0-3 14 | // uses BLLED_REG0_BANK(n) macro 15 | #define BLLED_REG0_STATUS_BIT 15 16 | #define BLLED_REG0_STATUS_MSK (0x8000) 17 | 18 | #define BLLED_REG0_CLKSEL_BIT 13 19 | #define BLLED_REG0_CLKSEL_MSK (0x2000) 20 | 21 | #define BLLED_REG0_CLK_MODE_BIT 12 22 | #define BLLED_REG0_CLK_MODE_MSK (0x1000) 23 | 24 | #define BLLED_REG0_DOUBLE_BIT 8 25 | #define BLLED_REG0_DOUBLE_MSK (0x100) 26 | 27 | #define BLLED_REG0_STEP_BIT 4 28 | #define BLLED_REG0_STEP_MSK (0x70) // 3-bit step value 29 | 30 | #define BLLED_REG0_CHOP_ENB_BIT 2 31 | #define BLLED_REG0_CHOP_ENB_MSK (0x4) 32 | 33 | #define BLLED_REG0_MODE_BIT 1 34 | #define BLLED_REG0_MODE_MSK (0x2) 35 | 36 | #define BLLED_REG0_EN_BIT 0 37 | #define BLLED_REG0_EN_MSK (0x1) 38 | 39 | // uses BLLED_REG1_BANK(n) macro 40 | #define BLLED_REG1_STP_MODE_BIT 1 41 | #define BLLED_REG1_STP_MODE_MSK (0x2) 42 | 43 | #define BLLED_REG1_PHASE_MODE_BIT 0 44 | #define BLLED_REG1_PHASE_MODE_MSK (0x1) 45 | 46 | 47 | //// gang-operations on all BLLEDs 48 | 49 | #define BLLED_GANG_REG0_RSV_BIT 8 50 | #define BLLED_GANG_REG0_RSV_MSK (0xF00) // 4 bits 51 | 52 | #define BLLED_GANG_REG0_STEP_TC_BIT 4 53 | #define BLLED_GANG_REG0_STEP_TC_MSK (0x30) // 2 bits 54 | 55 | #define BLLED_GANG_REG0_PHASE_TC_BIT 0 56 | #define BLLED_GANG_REG0_PHASE_TC_MSK (0x3) // 2 bits 57 | 58 | #define BLLED_GANG_REG2_TRIM_SEL_BIT 8 59 | #define BLLED_GANG_REG2_TRIM_SEL_MSK (0x700) // 3 bits 60 | 61 | #define BLLED_GANG_REG2_TRIM_EN_BIT 0 62 | #define BLLED_GANG_REG2_TRIM_EN_MSK (0x1) 63 | 64 | 65 | #endif /* __FV_BL_H__ */ 66 | -------------------------------------------------------------------------------- /include/fernvale-clockgate.h: -------------------------------------------------------------------------------- 1 | #ifndef __FV_CLOCKGATE_H__ 2 | #define __FV_CLOCKGATE_H__ 3 | 4 | // Clock gates are modifiable only via _SET and _CLEAR methods. 5 | // Don't try writing to the clockgate register itself! 6 | 7 | // control set 0 8 | #define CLKGATE_SYS_CTL0 (0xA0010000 + 0x0300) 9 | #define CLKGATE_SYS_CTL0_SET (0xA0010000 + 0x0310) // turns the block off 10 | #define CLKGATE_SYS_CTL0_CLR (0xA0010000 + 0x0320) // turns the block on 11 | 12 | #define CLKGATE_CTL0_LCD 0x0001 13 | #define CLKGATE_CTL0_RESIZER 0x0002 14 | #define CLKGATE_CTL0_ROTDMA 0x0004 15 | #define CLKGATE_CTL0_CAM_BCLK 0x0008 16 | #define CLKGATE_CTL0_PAD2CAM 0x0010 17 | #define CLKGATE_CTL0_G2D 0x0020 18 | #define CLKGATE_CTL0_MM_COLOR 0x0040 19 | #define CLKGATE_CTL0_SLCD 0x0080 20 | #define CLKGATE_CTL0_MD2G_26M 0x0100 21 | #define CLKGATE_CTL0_BT_26M 0x0200 22 | #define CLKGATE_CTL0_CAM_48M 0x0400 23 | #define CLKGATE_CTL0_DMA2SFC 0x0800 24 | #define CLKGATE_CTL0_2GDMA2SFC 0x1000 25 | #define CLKGATE_CTL0_BT_BUS 0x2000 26 | #define CLKGATE_CTL0_BT_ARM7 0x8000 27 | 28 | // control set 1 29 | #define CLKGATE_SYS_CTL1 (0xA0010000 + 0x0304) 30 | #define CLKGATE_SYS_CTL1_SET (0xA0010000 + 0x0314) 31 | #define CLKGATE_SYS_CTL2_CLR (0xA0010000 + 0x0328) 32 | 33 | #define CLKGATE_CTL1_SEJ 0x0001 34 | #define CLKGATE_CTL1_DMA 0x0002 35 | #define CLKGATE_CTL1_USB 0x0004 36 | #define CLKGATE_CTL1_MSDC 0x0008 37 | #define CLKGATE_CTL1_SIM 0x0010 38 | #define CLKGATE_CTL1_SIM2 0x0020 39 | #define CLKGATE_CTL1_I2C 0x0040 40 | #define CLKGATE_CTL1_SPI 0x0080 41 | #define CLKGATE_CTL1_OSTIMER 0x0100 42 | #define CLKGATE_CTL1_HIF1 0x0200 43 | #define CLKGATE_CTL1_UART1 0x2000 44 | #define CLKGATE_CTL1_UART2 0x4000 45 | 46 | // control set 2 47 | #define CLKGATE_SYS_CTL2 (0xA0010000 + 0x0308) 48 | #define CLKGATE_SYS_CTL2_SET (0xA0010000 + 0x0318) 49 | #define CLKGATE_SYS_CTL1_CLR (0xA0010000 + 0x0324) 50 | 51 | #define CLKGATE_CTL2_PWM 0x0001 52 | #define CLKGATE_CTL2_BTIF 0x0002 53 | #define CLKGATE_CTL2_GPT 0x0004 54 | #define CLKGATE_CTL2_AUXADC 0x0008 55 | #define CLKGATE_CTL2_LZMA 0x0010 56 | #define CLKGATE_CTL2_ROM 0x0020 57 | #define CLKGATE_CTL2_EFUSE 0x0040 58 | #define CLKGATE_CTL2_SW_LPM 0x0080 59 | #define CLKGATE_CTL2_NFI 0x0200 60 | #define CLKGATE_CTL2_MSDC2 0x0400 61 | #define CLKGATE_CTL2_SFC 0x0800 62 | #define CLKGATE_CTL2_SPI_NAND 0x1000 63 | #define CLKGATE_CTL2_FM_F26M 0x2000 64 | #define CLKGATE_CTL2_FM_BCLK 0x4000 65 | 66 | /* Audio */ 67 | 68 | #define CLKGATE_AUDIO_CG_CTL0 (0x82C00000+0x0000) 69 | #define CLKGATE_AUDIO_CG_CTL2 (0x82C00000+0x0008) 70 | #define CLKGATE_AUDIO_CG_CTL4 (0x82C00000+0x0030) 71 | 72 | #define CLKGATE_AUDIO_CG_CTL0_SET (0x82C00000+0x0010) 73 | #define CLKGATE_AUDIO_CG_CTL2_SET (0x82C00000+0x0018) 74 | #define CLKGATE_AUDIO_CG_CTL4_SET (0x82C00000+0x0034) 75 | 76 | #define CLKGATE_AUDIO_CG_CTL0_CLR (0x82C00000+0x0020) 77 | #define CLKGATE_AUDIO_CG_CTL2_CLR (0x82C00000+0x0028) 78 | #define CLKGATE_AUDIO_CG_CTL4_CLR (0x82C00000+0x0038) 79 | 80 | #define AUDIO_CG_CTL0_GCC 0x0002 81 | #define AUDIO_CG_CTL0_IRDMA 0x0040 82 | #define AUDIO_CG_CTL0_RXBUF 0x0100 83 | #define AUDIO_CG_CTL0_TXBUF 0x0200 84 | #define AUDIO_CG_CTL0_IRDBG 0x2000 85 | #define AUDIO_CG_CTL0_AHB2DSPIO 0x8000 86 | 87 | #define AUDIO_CG_CTL2_APC_PRE 0x0020 88 | #define AUDIO_CG_CTL2_VAFE 0x0100 89 | #define AUDIO_CG_CTL2_BFE 0x0200 90 | 91 | #define AUDIO_CG_CTL4_APC 0x0020 92 | #define AUDIO_CG_CTL4_VAFE 0x0100 93 | #define AUDIO_CG_CTL4_BFE 0x0200 94 | 95 | /* Analog */ 96 | 97 | #define CLKGATE_ANALOG_CLK_CTL0 (0xA0730000+0x0008) 98 | 99 | #define CLKGATE_ANALOG_CLK_SET0 (0xA0730000+0x000C) 100 | 101 | #define CLKGATE_ANALOG_CLK_CLR0 (0xA0730000+0x0010) 102 | 103 | #define CLKGATE_ANALOG_CTL0_PWM2 0x0002 104 | #define CLKGATE_ANALOG_CTL0_PWM3 0x0001 105 | #define CLKGATE_ANALOG_CTL0_AUXADC_BCLK 0x0004 106 | #define CLKGATE_ANALOG_CTL0_TP_BCLK 0x0008 107 | #define CLKGATE_ANALOG_CTL0_PMU_F26M 0x0010 108 | 109 | /* Multimedia (?) */ 110 | 111 | #define CLKGATE_MULTIMEDIA_CG_CTL CLKGATE_SYS_CTL0 112 | 113 | #define CLKGATE_MULTIMEDIA_CG_SET CLKGATE_SYS_CTL0_SET 114 | 115 | #define CLKGATE_MULTIMEDIA_CG_CLR CLKGATE_SYS_CTL0_CLR 116 | 117 | #define MULTIMEDIA_CG_CTL_G2D CLKGATE_CTL0_SW_G2D 118 | #define MULTIMEDIA_CG_CTL_LCD CLKGATE_CTL0_SW_LCD 119 | #define MULTIMEDIA_CG_CTL_MM_COLOR CLKGATE_CTL0_SW_MM_COLOR 120 | 121 | /* GSM Modem */ 122 | 123 | #define CLKGATE_MODEMGSM_CG_CTL2 (0x83000000+0x0008) 124 | #define CLKGATE_MODEMGSM_CG_CTL4 (0x83000000+0x0088) 125 | 126 | #define CLKGATE_MODEMGSM_CG_SET2 (0x83000000+0x0028) 127 | #define CLKGATE_MODEMGSM_CG_SET4 (0x83000000+0x00A8) 128 | 129 | #define CLKGATE_MODEMGSM_CG_CLR2 (0x83000000+0x0018) 130 | #define CLKGATE_MODEMGSM_CG_CLR4 (0x83000000+0x0098) 131 | 132 | #define MODEMGSM_CG_CTL2_TDMA 0x0001 133 | #define MODEMGSM_CG_CTL2_BSI_T 0x0004 134 | #define MODEMGSM_CG_CTL2_BPI_T 0x0008 135 | #define MODEMGSM_CG_CTL2_DIV 0x0800 136 | #define MODEMGSM_CG_CTL2_FCS 0x1000 137 | #define MODEMGSM_CG_CTL2_GCU 0x2000 138 | 139 | #define MODEMGSM_CG_CTL4_BSI 0x0004 140 | #define MODEMGSM_CG_CTL4_BPI 0x0008 141 | 142 | #endif /* __FV_CLOCKGATE_H__ */ 143 | -------------------------------------------------------------------------------- /include/fernvale-emi.h: -------------------------------------------------------------------------------- 1 | #ifndef __FV_EMI_H__ 2 | #define __FV_EMI_H__ 3 | 4 | /* Register names based off of: 5 | * https://github.com/dragonpt/lenovo_A390_mt6577_uboot_kernel/blob 6 | * /master/mediatek/custom 7 | * /huaqin77_cu_a510_ics2/preloader/inc/mt6577_emi_reg.h 8 | */ 9 | 10 | /* Note: MT6260 has only bank 1 */ 11 | #define EMI_CTRL_ADDR 0xa0050000 12 | #define EMI_CTRL_CONA (EMI_CTRL_ADDR + 0x00) /* Bank 0 control (low) */ 13 | #define EMI_CTRL_CONB (EMI_CTRL_ADDR + 0x08) /* Bank 1 control (low) */ 14 | #define EMI_CTRL_CONC (EMI_CTRL_ADDR + 0x10) /* Bank 2 control (low) */ 15 | #define EMI_CTRL_COND (EMI_CTRL_ADDR + 0x18) /* Bank 3 control (low) */ 16 | #define EMI_CTRL_CONE (EMI_CTRL_ADDR + 0x20) /* Bank 0 control (high) */ 17 | #define EMI_CTRL_CONF (EMI_CTRL_ADDR + 0x28) /* Bank 1 control (high) */ 18 | #define EMI_CTRL_CONG (EMI_CTRL_ADDR + 0x30) /* Bank 2 control (high) */ 19 | #define EMI_CTRL_CONH (EMI_CTRL_ADDR + 0x38) /* Bank 3 control (high) */ 20 | #define EMI_CTRL_CONI (EMI_CTRL_ADDR + 0x40) /* Bank 0 control for mDDR */ 21 | #define EMI_CTRL_CONJ (EMI_CTRL_ADDR + 0x48) /* Bank 1 control for mDDR */ 22 | #define EMI_CTRL_CONK (EMI_CTRL_ADDR + 0x50) /* Bank 2 control for mDDR */ 23 | #define EMI_CTRL_CONL (EMI_CTRL_ADDR + 0x58) /* Bank 3 control for mDDR */ 24 | #define EMI_CTRL_CONM (EMI_CTRL_ADDR + 0x60) /* */ 25 | #define EMI_CTRL_GENA (EMI_CTRL_ADDR + 0x70) /* General control register 0 */ 26 | #define EMI_CTRL_GENB (EMI_CTRL_ADDR + 0x78) /* General control register 1 */ 27 | #define EMI_CTRL_ADMUX (EMI_CTRL_ADDR + 0x80) /* Something involving GPIO mux */ 28 | #define EMI_CTRL_RDCT (EMI_CTRL_ADDR + 0x88) 29 | #define EMI_CTRL_DLLV (EMI_CTRL_ADDR + 0x90) 30 | #define EMI_CTRL_IDLA (EMI_CTRL_ADDR + 0xc0) 31 | #define EMI_CTRL_IDLB (EMI_CTRL_ADDR + 0xc8) 32 | #define EMI_CTRL_IDLC (EMI_CTRL_ADDR + 0xd0) 33 | #define EMI_CTRL_IDLD (EMI_CTRL_ADDR + 0xd8) 34 | #define EMI_CTRL_IDLE (EMI_CTRL_ADDR + 0xe0) 35 | #define EMI_CTRL_ODLA (EMI_CTRL_ADDR + 0xe8) 36 | #define EMI_CTRL_ODLB (EMI_CTRL_ADDR + 0xf0) 37 | #define EMI_CTRL_ODLC (EMI_CTRL_ADDR + 0xf8) 38 | #define EMI_CTRL_ODLD (EMI_CTRL_ADDR + 0x100) 39 | #define EMI_CTRL_ODLE (EMI_CTRL_ADDR + 0x108) 40 | #define EMI_CTRL_ODLF (EMI_CTRL_ADDR + 0x110) 41 | #define EMI_CTRL_IOA (EMI_CTRL_ADDR + 0x130) 42 | #define EMI_CTRL_IOB (EMI_CTRL_ADDR + 0x138) 43 | #define EMI_CTRL_DSRAM (EMI_CTRL_ADDR + 0x150) 44 | #define EMI_CTRL_ARBA (EMI_CTRL_ADDR + 0x170) 45 | #define EMI_CTRL_ARBB (EMI_CTRL_ADDR + 0x178) 46 | #define EMI_CTRL_ARBC (EMI_CTRL_ADDR + 0x180) 47 | #define EMI_CTRL_SLCT (EMI_CTRL_ADDR + 0x198) 48 | #define EMI_CTRL_ABCT (EMI_CTRL_ADDR + 0x1a0) 49 | #define EMI_CTRL_BMEN (EMI_CTRL_ADDR + 0x200) 50 | #define EMI_CTRL_BCNT (EMI_CTRL_ADDR + 0x208) 51 | #define EMI_CTRL_TACT (EMI_CTRL_ADDR + 0x210) 52 | #define EMI_CTRL_TSCT (EMI_CTRL_ADDR + 0x218) 53 | #define EMI_CTRL_WACT (EMI_CTRL_ADDR + 0x220) 54 | #define EMI_CTRL_WSCT (EMI_CTRL_ADDR + 0x228) 55 | #define EMI_CTRL_BACT (EMI_CTRL_ADDR + 0x230) 56 | #define EMI_CTRL_BSCT0 (EMI_CTRL_ADDR + 0x238) 57 | #define EMI_CTRL_BSCT1 (EMI_CTRL_ADDR + 0x240) 58 | #define EMI_CTRL_TTYPE1 (EMI_CTRL_ADDR + 0x280) 59 | #define EMI_CTRL_TTYPE2 (EMI_CTRL_ADDR + 0x288) 60 | #define EMI_CTRL_TTYPE3 (EMI_CTRL_ADDR + 0x290) 61 | #define EMI_CTRL_TTYPE4 (EMI_CTRL_ADDR + 0x298) 62 | #define EMI_CTRL_TTYPE5 (EMI_CTRL_ADDR + 0x2a0) 63 | #define EMI_CTRL_TTYPE6 (EMI_CTRL_ADDR + 0x2a8) 64 | #define EMI_CTRL_TTYPE7 (EMI_CTRL_ADDR + 0x2b0) 65 | #define EMI_CTRL_TTYPE8 (EMI_CTRL_ADDR + 0x2b8) 66 | #define EMI_CTRL_TTYPE9 (EMI_CTRL_ADDR + 0x2c0) 67 | #define EMI_CTRL_TTYPE10 (EMI_CTRL_ADDR + 0x2c8) 68 | #define EMI_CTRL_TTYPE11 (EMI_CTRL_ADDR + 0x2d0) 69 | #define EMI_CTRL_TTYPE12 (EMI_CTRL_ADDR + 0x2d8) 70 | #define EMI_CTRL_TTYPE13 (EMI_CTRL_ADDR + 0x2e0) 71 | #define EMI_CTRL_TTYPE14 (EMI_CTRL_ADDR + 0x2e8) 72 | #define EMI_CTRL_TTYPE15 (EMI_CTRL_ADDR + 0x2f0) 73 | #define EMI_CTRL_TTYPE16 (EMI_CTRL_ADDR + 0x2f8) 74 | 75 | #define EMI_CTRL_MBISTA (EMI_CTRL_ADDR + 0x300) 76 | #define EMI_CTRL_MBISTA_PATTERN_SHIFT 16 77 | #define EMI_CTRL_MBISTA_PATTERN_MASK 0xffff0000 78 | 79 | #define EMI_CTRL_MBISTB (EMI_CTRL_ADDR + 0x308) 80 | #define EMI_CTRL_MBISTB_START_KEY 0x325 81 | #define EMI_CTRL_MBISTB_RANDOMIZE (1 << 12) 82 | #define EMI_CTRL_MBISTB_INVERT (1 << 13) 83 | 84 | #define EMI_CTRL_MBISTC (EMI_CTRL_ADDR + 0x310) 85 | 86 | #define EMI_CTRL_MBISTD (EMI_CTRL_ADDR + 0x318) 87 | #define EMI_CTRL_MBISTD_FAILURE (1 << 0) 88 | #define EMI_CTRL_MBISTD_FINISHED (1 << 1) 89 | 90 | 91 | 92 | #define EMI_CTRL_TEST (EMI_CTRL_ADDR + 0x330) 93 | 94 | #define EMI_CTRL_REMAP (0xA0510000) 95 | 96 | #endif /* __FV_EMI_H__ */ 97 | -------------------------------------------------------------------------------- /include/fernvale-kbd.h: -------------------------------------------------------------------------------- 1 | #ifndef __FV_KBD_H__ 2 | #define __FV_KBD_H__ 3 | 4 | /// The BIG_LED is a 60mA drive-capable open-drain switch 5 | /// it's useful for driving circuits such as an array of LEDs 6 | /// used to illuminate a keyboard, hence its inclusion in the 7 | /// keyboard section. However, on PCBs with no keyboard, it's 8 | /// simply a big LED driver. 9 | 10 | #define BIG_LED_ADDR (0xA0700000 + 0x0C80) 11 | #define BIG_LED_ON (0x3) 12 | #define BIG_LED_OFF (0x0) 13 | 14 | #define KBD_ADDR 0xA00D0000 15 | #define KBD_STATUS (KBD_ADDR + 0x0000) 16 | #define KBD_MEM1 (KBD_ADDR + 0x4) 17 | #define KBD_MEM2 (KBD_ADDR + 0x8) 18 | #define KBD_MEM3 (KBD_ADDR + 0xc) 19 | #define KBD_MEM4 (KBD_ADDR + 0x10) 20 | #define KBD_MEM5 (KBD_ADDR + 0x14) 21 | #define KBD_DEBOUNCING (KBD_ADDR + 0x18) 22 | #define KBD_SCAN_TIME_ADJ (KBD_ADDR + 0x1c) 23 | #define KBD_1OR2 (KBD_ADDR + 0x20) 24 | #define KBD_ENABLE (KBD_ADDR + 0x24) 25 | 26 | 27 | #endif /* __FV_KBD_H__ */ 28 | -------------------------------------------------------------------------------- /include/fernvale-lcd.h: -------------------------------------------------------------------------------- 1 | #ifndef __FV_LCD_H__ 2 | #define __FV_LCD_H__ 3 | 4 | // don't take values in here as gospel. some may be incorrect due to 5 | // misinterpertation of reverse engineered values 6 | 7 | #define LCD_CTRL_ADDR 0xa0450000 8 | 9 | #define LCD_STATUS_REG (LCD_CTRL_ADDR+0x0000) 10 | #define LCD_STATUS_RUN_BIT (0x1) 11 | #define LCD_STATUS_WAIT_CMDQ_BIT (0x2) 12 | #define LCD_STATUS_WAIT_HTT_BIT (0x8) 13 | #define LCD_STATUS_TE_PENDING_BIT (0x10) 14 | #define LCD_STATUS_BUSY_BIT (0x20) 15 | #define LCD_STATUS_GMC_REQ_BIT (0x40) 16 | 17 | #define LCD_INT_ENA_REG (LCD_CTRL_ADDR+0x0004) 18 | #define LCD_INT_ENA_TRIG_BIT (0x1) 19 | #define LCD_INT_ENA_REG_TRIG_BIT (0x2) 20 | #define LCD_INT_ENA_CMD_TRIG_BIT (0x4) 21 | #define LCD_INT_ENA_HTT_TRIG_BIT (0x10) 22 | #define LCD_INT_ENA_HSYNC_TRIG_BIT (0x20) 23 | #define LCD_INT_ENA_VSYNC_TRIG_BIT (0x20) 24 | 25 | #define LCD_INT_STAT_REG (LCD_CTRL_ADDR+0x0008) 26 | #define LCD_INT_STAT_DONE_BIT (0x1) 27 | 28 | #define LCD_RUN_REG (LCD_CTRL_ADDR+0x000C) 29 | #define LCD_RUN_BIT (0x8000) 30 | 31 | #define LCD_RESET_REG (LCD_CTRL_ADDR+0x0010) 32 | #define LCD_RESET_MASK (1 << 0) 33 | #define LCD_RESET_SET (0 << 0) 34 | #define LCD_RESET_CLEAR (1 << 0) 35 | 36 | #define LCD_PAR0_CFG_REG (LCD_CTRL_ADDR+0x0030) 37 | #define LCD_PAR1_CFG_REG (LCD_CTRL_ADDR+0x0034) 38 | #define LCD_PAR_CFG_WR_WAIT_CYC_MASK (0x3F) 39 | #define LCD_PAR_CFG_WR_WAIT_CYC_BIT (0) 40 | #define LCD_PAR_CFG_WR_TSU_MASK (0xF00) 41 | #define LCD_PAR_CFG_WR_TSU_BIT (8) 42 | #define LCD_PAR_CFG_WR_TH_MASK (0xF000) 43 | #define LCD_PAR_CFG_WR_TH_BIT (12) 44 | #define LCD_PAR_CFG_RD_LATENCY_CYC_MASK (0x3F0000) 45 | #define LCD_PAR_CFG_RD_LATENCY_CYC_BIT (16) 46 | #define LCD_PAR_CFG_RD_TSU_MASK (0xF000000) 47 | #define LCD_PAR_CFG_RD_TSU_BIT (24) 48 | #define LCD_PAR_CFG_RD_TH_MASK (0xF0000000) 49 | #define LCD_PAR_CFG_RD_TH_BIT (28) 50 | 51 | #define LCD_PAR_DATA_WIDTH_REG (LCD_CTRL_ADDR+0x003C) 52 | #define LCD_PAR_BUS_WIDTH0_MASK (0x7) 53 | #define LCD_PAR_BUS_WIDTH0_BIT (0) 54 | #define LCD_PAR_BUS_WIDTH1_MASK (0x70) 55 | #define LCD_PAR_BUS_WIDTH1_BIT (4) 56 | #define LCD_PAR_W2W_WAIT0_MASK (0xF0000) 57 | #define LCD_PAR_W2W_WAIT0_BIT (16) 58 | #define LCD_PAR_W2W_WAIT1_MASK (0xF00000) 59 | #define LCD_PAR_W2W_WAIT1_BIT (20) 60 | #define LCD_PAR_BUS_WIDTH_8BIT (0) 61 | #define LCD_PAR_BUS_WIDTH_9BIT (1) 62 | #define LCD_PAR_BUS_WIDTH_16BIT (2) 63 | #define LCD_PAR_BUS_WIDTH_18BIT (3) 64 | 65 | #define LCD_TEARING_SYNC_CALC_REG (LCD_CTRL_ADDR+0x0044) 66 | 67 | #define LCD_TEARING_LCD_SIZE_REG (LCD_CTRL_ADDR+0x0048) 68 | #define LCD_TEARING_LCD_SIZE_HTIME_SHIFT 0 69 | #define LCD_TEARING_LCD_SIZE_HTIME_MASK 0x3ff 70 | #define LCD_TEARING_LCD_SIZE_VTIME_SHIFT 16 71 | #define LCD_TEARING_LCD_SIZE_VTIME_MASK 0x0fff0000 72 | 73 | #define LCD_TEARING_SYNC_CNT_REG (LCD_CTRL_ADDR+0x004C) 74 | 75 | #define LCD_TEARING_REG (LCD_CTRL_ADDR+0x0050) 76 | #define LCD_TEARING_ENABLE (1 << 0) 77 | #define LCD_TEARING_POLARITY (1 << 1) 78 | #define LCD_TEARING_MODE_VSYNC (1 << 2) /* Might be inverted */ 79 | #define LCD_TEARING_MODE_HSYNC (0 << 2) /* Might be inverted */ 80 | #define LCD_TEARING_SW_FORCE_BIT (1 << 15) 81 | 82 | #define LCD_GMC_CTRL_REG (LCD_CTRL_ADDR+0x0054) 83 | #define LCD_GMC_CTRL_BURST_4BYTE (0 << 0) 84 | #define LCD_GMC_CTRL_BURST_16BYTE (2 << 0) 85 | #define LCD_GMC_CTRL_BURST_32BYTE (3 << 0) 86 | #define LCD_GMC_CTRL_BURST_64BYTE (4 << 0) 87 | #define LCD_GMC_CTRL_ENABLE (1 << 4) 88 | #define LCD_GMC_CTRL_PERIOD_MASK (0xffff0000) 89 | #define LCD_GMC_CTRL_PERIOD_SHIFT 16 90 | 91 | #define LCD_AUTOCOPY_CTRL_REG (LCD_CTRL_ADDR+0x0080) 92 | // should be: 93 | // 0 - BGR 94 | // 0 - significance (?) 95 | // 1 - padding on MSBs 96 | // 010 - RGB565 (100 for RGB888, 011 for RGB66) 97 | // 10 - 9-bit interface 98 | // 000000 - command (no commands now) 99 | // 0 -- disable W2M 100 | // 0 -- enable commands 101 | // 00000010 -- 2 cycle waiting period (may be ok to set 0 but for now set to 2) 102 | // 1 -- send residue mode, residue per frame 103 | // 0 104 | // 1 -- enable frame update counter. why not? 105 | // 0 106 | // 1000 -- enable layer 0 only 107 | // 1000 0101 0000 0010 1000 0000 1001 0100 = 0x85028094 108 | 109 | #define LCD_AUTOCOPY_CTRL_FORMAT_MASK 0x020000FF 110 | 111 | /* Pixel ordering */ 112 | #define LCD_AUTOCOPY_CTRL_FORMAT_RGB (0 << 0) 113 | #define LCD_AUTOCOPY_CTRL_FORMAT_BGR (1 << 0) 114 | 115 | /* Format when sending across wire */ 116 | #define LCD_AUTOCOPY_CTRL_FORMAT_MSB (0 << 1) 117 | #define LCD_AUTOCOPY_CTRL_FORMAT_LSB (1 << 1) 118 | 119 | /* If padding is needed, where to add padding */ 120 | #define LCD_AUTOCOPY_CTRL_FORMAT_PAD_LSB (0 << 2) 121 | #define LCD_AUTOCOPY_CTRL_FORMAT_PAD_MSB (1 << 2) 122 | 123 | #define LCD_AUTOCOPY_CTRL_FORMAT_RGB332 (0b000 << 3) 124 | #define LCD_AUTOCOPY_CTRL_FORMAT_RGB444 (0b001 << 3) 125 | #define LCD_AUTOCOPY_CTRL_FORMAT_RGB565 (0b010 << 3) 126 | #define LCD_AUTOCOPY_CTRL_FORMAT_RGB666 (0b011 << 3) 127 | #define LCD_AUTOCOPY_CTRL_FORMAT_RGB888 (0b100 << 3) 128 | 129 | #define LCD_AUTOCOPY_CTRL_FORMAT_IFACE_8BIT (0b00 << 6) 130 | #define LCD_AUTOCOPY_CTRL_FORMAT_IFACE_16BIT (0b01 << 6) 131 | #define LCD_AUTOCOPY_CTRL_FORMAT_IFACE_9BIT (0b10 << 6) 132 | #define LCD_AUTOCOPY_CTRL_FORMAT_IFACE_18BIT (0b11 << 6) 133 | 134 | /* Support prefixing LCD data with command/data bytes */ 135 | #define LCD_AUTOCOPY_CTRL_CMD_COUNT_SHIFT 8 136 | #define LCD_AUTOCOPY_CTRL_CMD_COUNT_MASK 0x00003f00 137 | 138 | /* Enable writing to memory, in addition to writing to LCD module */ 139 | #define LCD_AUTOCOPY_CTRL_W2M (1 << 14) 140 | 141 | /* Enable sending command bytes. */ 142 | #define LCD_AUTOCOPY_CTRL_ENC (1 << 15) 143 | 144 | /* Waiting period between two consecutive data/command transfers */ 145 | #define LCD_AUTOCOPY_CTRL_PERIOD_SHIFT 16 146 | #define LCD_AUTOCOPY_CTRL_PERIOD_MASK 0x00ff0000 147 | 148 | /* Send residue per frame */ 149 | #define LCD_AUTOCOPY_CTRL_SEND_RESIDUE (1 << 24) 150 | 151 | #define LCD_AUTOCOPY_CTRL_COLOR_MODE (1 << 26) 152 | 153 | #define LCD_AUTOCOPY_CTRL_EN3 (1 << 28) 154 | #define LCD_AUTOCOPY_CTRL_EN2 (1 << 29) 155 | #define LCD_AUTOCOPY_CTRL_EN1 (1 << 30) 156 | #define LCD_AUTOCOPY_CTRL_EN0 (1 << 31) 157 | #define LCD_AUTOCOPY_CTRL_LAYER_MASK 0xf0000000 158 | 159 | /* Set to 0, uint 32 */ 160 | #define LCD_AUTOCOPY_OFFSET_REG (LCD_CTRL_ADDR+0x0084) 161 | 162 | /* Address to write commands to, when running with LCD_AUTOCOPY_CTRL_ENC */ 163 | #define LCD_AUTOCOPY_CMD_ADDR_REG (LCD_CTRL_ADDR+0x0088) 164 | 165 | /* Address to write data to, when running with LCD_AUTOCOPY_CTRL_ENC */ 166 | #define LCD_AUTOCOPY_DATA_ADDR_REG (LCD_CTRL_ADDR+0x008C) 167 | 168 | /* Set to 0x014000F0, uint32 (320x240) */ 169 | #define LCD_AUTOCOPY_SIZE_REG (LCD_CTRL_ADDR+0x0090) 170 | 171 | /* Set to 0x80008000 (slight greenish) */ 172 | #define LCD_AUTOCOPY_BG_COLOR_REG (LCD_CTRL_ADDR+0x009C) 173 | 174 | #define LCD_LAYER0_CTRL_REG (LCD_CTRL_ADDR+0x00B0) 175 | #define LCD_LAYER_CTRL_OPA_MASK (0xff) 176 | #define LCD_LAYER_CTRL_OPA_SHIFT 0 177 | #define LCD_LAYER_CTRL_OPA_EN (1 << 8) 178 | #define LCD_LAYER_CTRL_ROT0 (0 << 11) 179 | #define LCD_LAYER_CTRL_ROT90 (1 << 11) 180 | #define LCD_LAYER_CTRL_ROT180 (2 << 11) 181 | #define LCD_LAYER_CTRL_ROT270 (3 << 11) 182 | #define LCD_LAYER_CTRL_HFLIP (1 << 13) 183 | #define LCD_LAYER_CTRL_SRC_KEY_EN (1 << 14) 184 | #define LCD_LAYER_CTRL_DST_KEY_EN (1 << 14) 185 | #define LCD_LAYER_CTRL_DATA_SWAP_EN (1 << 16) 186 | #define LCD_LAYER_CTRL_DITHER_EN (1 << 18) 187 | #define LCD_LAYER_CTRL_CLRDPT_8BPP (0 << 20) 188 | #define LCD_LAYER_CTRL_CLRDPT_RGB565 (1 << 20) 189 | #define LCD_LAYER_CTRL_CLRDPT_UYVY422 (2 << 20) 190 | #define LCD_LAYER_CTRL_CLRDPT_RGB888 (3 << 20) 191 | #define LCD_LAYER_CTRL_CLRDPT_ARGB8888 (4 << 20) 192 | #define LCD_LAYER_CTRL_CLRDPT_PARGB8888 (5 << 20) 193 | #define LCD_LAYER_CTRL_CLRDPT_XRGB (6 << 20) 194 | #define LCD_LAYER_CTRL_CLRDPT_ARGB6666 (7 << 20) 195 | #define LCD_LAYER_CTRL_CLRDPT_PARGB6666 (8 << 20) 196 | #define LCD_LAYER_CTRL_CLRDPT_MONO (9 << 20) 197 | #define LCD_LAYER_CTRL_SWP (1 << 24) 198 | 199 | 200 | #define LCD_LAYER0_SRC_KEY_REG (LCD_CTRL_ADDR+0x00B4) 201 | #define LCD_LAYER0_OFFSET_REG (LCD_CTRL_ADDR+0x00B8) 202 | #define LCD_LAYER0_SRC_ADDR_REG (LCD_CTRL_ADDR+0x00BC) 203 | #define LCD_LAYER0_SIZE_REG (LCD_CTRL_ADDR+0x00C0) 204 | #define LCD_LAYER0_MEM_OFFSET_REG (LCD_CTRL_ADDR+0x00C8) 205 | #define LCD_LAYER0_PITCH_REG (LCD_CTRL_ADDR+0x00CC) 206 | 207 | // there's 3 more layers, but I'm happy to just get one working for now... 208 | 209 | #define LCD_FRAME_COUNTER_CON_REG (LCD_CTRL_ADDR+0x0220) 210 | #define LCD_FRAME_COUNTER_CON_START (1 << 0) 211 | #define LCD_FRAME_COUNTER_CON_STOP (1 << 1) 212 | #define LCD_FRAME_COUNTER_REG (LCD_CTRL_ADDR+0x0224) 213 | 214 | #define LCD_FREERUN_CTRL_REG (LCD_CTRL_ADDR+0x0240) 215 | #define LCD_FREERUN_CTRL_ENABLE_DBI (1 << 0) 216 | #define LCD_FREERUN_CTRL_ENABLE_GMC (1 << 1) 217 | 218 | #define LCD_FREERUN_RATE_REG (LCD_CTRL_ADDR+0x0244) 219 | #define LCD_FREERUN_RATE_MASK (0x3ff) 220 | 221 | #define LCD_FREERUN_DBI_THRESH_REG (LCD_CTRL_ADDR+0x0248) 222 | #define LCD_FREERUN_DBI_THRESH_LOW_SHIFT 0 223 | #define LCD_FREERUN_DBI_THRESH_LOW_MASK (0xffff) 224 | #define LCD_FREERUN_DBI_THRESH_HIGH_SHIFT 16 225 | #define LCD_FREERUN_DBI_THRESH_HIGH_MASK (0xffff0000) 226 | 227 | #define LCD_FREERUN_GMC_THRESH_REG (LCD_CTRL_ADDR+0x0248) 228 | #define LCD_FREERUN_GMC_THRESH_LOW_SHIFT 0 229 | #define LCD_FREERUN_GMC_THRESH_LOW_MASK (0xffff) 230 | #define LCD_FREERUN_GMC_THRESH_HIGH_SHIFT 16 231 | #define LCD_FREERUN_GMC_THRESH_HIGH_MASK (0xffff0000) 232 | 233 | #define LCD_CMD_LIST_ADDR (LCD_CTRL_ADDR+0x0C00) 234 | 235 | #define LCD_PAR0_CMD_PORT_REG (LCD_CTRL_ADDR+0x0F00) 236 | #define LCD_PAR0_DAT_PORT_REG (LCD_CTRL_ADDR+0x0F10) 237 | #define LCD_PAR1_CMD_PORT_REG (LCD_CTRL_ADDR+0x0F20) 238 | #define LCD_PAR1_DAT_PORT_REG (LCD_CTRL_ADDR+0x0F30) 239 | 240 | #endif /* __FV_LCD_H__ */ 241 | -------------------------------------------------------------------------------- /include/fernvale-pll.h: -------------------------------------------------------------------------------- 1 | #ifndef __FV_PLL_H__ 2 | #define __FV_PLL_H__ 3 | 4 | /* Register names and values adapted from: 5 | * https://github.com/wiko-sources/cink-slim/blob 6 | * /master/mediatek/platform/mt6577 7 | * /kernel/core/include/mach/mt6577_clock_manager.h 8 | */ 9 | 10 | #define PLL_CTRL_ADDR 0xa0170000 11 | #define PLL_CLK_ADDR 0x80000100 12 | 13 | #define PLL_CTRL_XOSC_CON0 (PLL_CTRL_ADDR + 0x00) 14 | #define PLL_CTRL_XOSC_CON1 (PLL_CTRL_ADDR + 0x04) 15 | 16 | #define PLL_CTRL_CLKSQ_CON0 (PLL_CTRL_ADDR + 0x20) 17 | #define PLL_CTRL_CLKSQ_CON1 (PLL_CTRL_ADDR + 0x24) 18 | #define PLL_CTRL_CLKSQ_CON2 (PLL_CTRL_ADDR + 0x28) 19 | 20 | #define PLL_CTRL_CON0 (PLL_CTRL_ADDR + 0x40) 21 | #define PLL_CTRL_CON1 (PLL_CTRL_ADDR + 0x44) 22 | #define PLL_CTRL_CON2 (PLL_CTRL_ADDR + 0x48) 23 | #define PLL_CTRL_CON3 (PLL_CTRL_ADDR + 0x4c) 24 | #define PLL_CTRL_CON4 (PLL_CTRL_ADDR + 0x50) 25 | #define PLL_CTRL_CON5 (PLL_CTRL_ADDR + 0x54) 26 | #define PLL_CTRL_CON6 (PLL_CTRL_ADDR + 0x58) 27 | #define PLL_CTRL_CON7 (PLL_CTRL_ADDR + 0x5c) 28 | #define PLL_CTRL_CON8 (PLL_CTRL_ADDR + 0x5c) 29 | #define PLL_CTRL_CON9 (PLL_CTRL_ADDR + 0x5c) 30 | #define PLL_CTRL_CON10 (PLL_CTRL_ADDR + 0x5c) 31 | #define PLL_CTRL_CON11 (PLL_CTRL_ADDR + 0x5c) 32 | 33 | #define PLL_CTRL_DPM_CON0 (PLL_CTRL_ADDR + 0x90) 34 | #define PLL_CTRL_DPM_CON1 (PLL_CTRL_ADDR + 0x94) 35 | #define PLL_CTRL_DPM_CON2 (PLL_CTRL_ADDR + 0x98) 36 | 37 | #define PLL_CTRL_MPLL_CON0 (PLL_CTRL_ADDR + 0x100) 38 | #define PLL_CTRL_MPLL_CON1 (PLL_CTRL_ADDR + 0x104) 39 | #define PLL_CTRL_MPLL_CON2 (PLL_CTRL_ADDR + 0x108) 40 | 41 | #define PLL_CTRL_UPLL_CON0 (PLL_CTRL_ADDR + 0x140) 42 | #define PLL_CTRL_UPLL_CON1 (PLL_CTRL_ADDR + 0x144) 43 | #define PLL_CTRL_UPLL_CON2 (PLL_CTRL_ADDR + 0x148) 44 | 45 | #define PLL_CTRL_EPLL_CON0 (PLL_CTRL_ADDR + 0x180) 46 | #define PLL_CTRL_EPLL_CON1 (PLL_CTRL_ADDR + 0x184) 47 | #define PLL_CTRL_EPLL_CON2 (PLL_CTRL_ADDR + 0x188) 48 | 49 | #define PLL_CTRL_FH_CON0 (PLL_CTRL_ADDR + 0x500) 50 | #define PLL_CTRL_FH_CON1 (PLL_CTRL_ADDR + 0x504) 51 | #define PLL_CTRL_FH_CON2 (PLL_CTRL_ADDR + 0x508) 52 | #define PLL_CTRL_FH_CON3 (PLL_CTRL_ADDR + 0x50c) 53 | #define PLL_CTRL_FH_CON4 (PLL_CTRL_ADDR + 0x510) 54 | 55 | #define PLL_CTRL_MDDS_CON0 (PLL_CTRL_ADDR + 0x640) 56 | #define PLL_CTRL_MDDS_CON1 (PLL_CTRL_ADDR + 0x644) 57 | #define PLL_CTRL_MDDS_CON2 (PLL_CTRL_ADDR + 0x648) 58 | 59 | #define PLL_CTRL_EDDS_CON0 (PLL_CTRL_ADDR + 0x680) 60 | #define PLL_CTRL_EDDS_CON1 (PLL_CTRL_ADDR + 0x684) 61 | #define PLL_CTRL_EDDS_CON2 (PLL_CTRL_ADDR + 0x688) 62 | 63 | #define PLL_CTRL_CLK_CONDA (PLL_CLK_ADDR + 0x00) 64 | #define PLL_CTRL_CLK_CONDB (PLL_CLK_ADDR + 0x04) 65 | #define PLL_CTRL_CLK_CONDC (PLL_CLK_ADDR + 0x08) 66 | #define PLL_CTRL_CLK_CONDD (PLL_CLK_ADDR + 0x0c) 67 | #define PLL_CTRL_CLK_CONDE (PLL_CLK_ADDR + 0x10) 68 | #define PLL_CTRL_CLK_CONDF (PLL_CLK_ADDR + 0x14) 69 | #define PLL_CTRL_CLK_CONDG (PLL_CLK_ADDR + 0x18) 70 | #define PLL_CTRL_CLK_CONDH (PLL_CLK_ADDR + 0x1c) 71 | 72 | #endif /* __FV_PLL_H__ */ 73 | -------------------------------------------------------------------------------- /include/fernvale-pmic.h: -------------------------------------------------------------------------------- 1 | #ifndef __FV_PMIC_H__ 2 | #define __FV_PMIC_H__ 3 | 4 | #define PMIC_ADDR 0xa0700a00 5 | #define PMIC_CTRL0 (PMIC_ADDR + 0x00) 6 | #define PMIC_CTRL1 (PMIC_ADDR + 0x04) 7 | #define PMIC_CTRL2 (PMIC_ADDR + 0x08) 8 | #define PMIC_CTRL3 (PMIC_ADDR + 0x0c) 9 | #define PMIC_CTRL4 (PMIC_ADDR + 0x10) 10 | #define PMIC_CTRL5 (PMIC_ADDR + 0x14) 11 | #define PMIC_CTRL6 (PMIC_ADDR + 0x18) 12 | #define PMIC_CTRL7 (PMIC_ADDR + 0x1c) 13 | #define PMIC_CTRL8 (PMIC_ADDR + 0x20) 14 | #define PMIC_CTRL9 (PMIC_ADDR + 0x24) 15 | #define PMIC_CTRL10 (PMIC_ADDR + 0x28) 16 | 17 | #endif /* __FV_PMIC_H__ */ 18 | -------------------------------------------------------------------------------- /include/fernvale-spi.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __FV_SPI_H__ 3 | #define __FV_SPI_H__ 4 | 5 | #define SPI_ADDR 0xa0140000 6 | 7 | #define SPI_BLOCKMODE (SPI_ADDR + 0x00) 8 | #define SPI_BLOCKMODE_BUSY (1 << 0) 9 | #define SPI_BLOCKMODE_PREP (1 << 1) 10 | #define SPI_BLOCKMODE_TRIGGER (1 << 2) 11 | #define SPI_BLOCKMODE_ENABLE (1 << 3) 12 | #define SPI_BLOCKMODE_QUAD (1 << 4) 13 | #define SPI_BLOCKMODE_RELEASE (1 << 16) 14 | #define SPI_BLOCKMODE_CS (0 << 28) 15 | #define SPI_BLOCKMODE_CS0 (0 << 28) 16 | #define SPI_BLOCKMODE_CS1 (1 << 28) 17 | 18 | #define SPI_PIO_CS0 (SPI_ADDR + 0x04) 19 | #define SPI_PIO_QUAD_ENABLE (1 << 0) 20 | #define SPI_PIO_CMD1_WIDE (1 << 1) 21 | #define SPI_PIO_CMD2_ON (1 << 2) 22 | #define SPI_PIO_CMD2_WIDE (1 << 3) 23 | #define SPI_PIO_MODE (7 << 4) 24 | #define SPI_PIO_MODE_SLOW (0 << 4) 25 | #define SPI_PIO_MODE_FAST (1 << 4) 26 | #define SPI_PIO_MODE_QUAD (7 << 4) 27 | #define SPI_PIO_CMD1_DUMMY_CYCLES_0 (0 << 8) 28 | #define SPI_PIO_CMD1_DUMMY_CYCLES_1 (1 << 8) 29 | #define SPI_PIO_CMD1_DUMMY_CYCLES_2 (2 << 8) 30 | #define SPI_PIO_CMD1_DUMMY_CYCLES_3 (3 << 8) 31 | #define SPI_PIO_CMD1_DUMMY_CYCLES_4 (4 << 8) 32 | #define SPI_PIO_CMD1_DUMMY_CYCLES_5 (5 << 8) 33 | #define SPI_PIO_CMD1_DUMMY_CYCLES_6 (6 << 8) 34 | #define SPI_PIO_CMD1_DUMMY_CYCLES_7 (7 << 8) 35 | #define SPI_PIO_CMD1_DUMMY_CYCLES_8 (8 << 8) 36 | #define SPI_PIO_CMD1_DUMMY_CYCLES_9 (9 << 8) 37 | #define SPI_PIO_CMD1_DUMMY_CYCLES_10 (10 << 8) 38 | #define SPI_PIO_CMD1_DUMMY_CYCLES_11 (11 << 8) 39 | #define SPI_PIO_CMD1_DUMMY_CYCLES_12 (12 << 8) 40 | #define SPI_PIO_CMD1_DUMMY_CYCLES_13 (13 << 8) 41 | #define SPI_PIO_CMD1_DUMMY_CYCLES_14 (14 << 8) 42 | #define SPI_PIO_CMD1_DUMMY_CYCLES_15 (15 << 8) 43 | #define SPI_PIO_CMD2_DUMMY_CYCLES_0 (0 << 12) 44 | #define SPI_PIO_CMD2_DUMMY_CYCLES_1 (1 << 12) 45 | #define SPI_PIO_CMD2_DUMMY_CYCLES_2 (2 << 12) 46 | #define SPI_PIO_CMD2_DUMMY_CYCLES_3 (3 << 12) 47 | #define SPI_PIO_CMD2_DUMMY_CYCLES_4 (4 << 12) 48 | #define SPI_PIO_CMD2_DUMMY_CYCLES_5 (5 << 12) 49 | #define SPI_PIO_CMD2_DUMMY_CYCLES_6 (6 << 12) 50 | #define SPI_PIO_CMD2_DUMMY_CYCLES_7 (7 << 12) 51 | #define SPI_PIO_CMD2_DUMMY_CYCLES_8 (8 << 12) 52 | #define SPI_PIO_CMD2_DUMMY_CYCLES_9 (9 << 12) 53 | #define SPI_PIO_CMD2_DUMMY_CYCLES_10 (10 << 12) 54 | #define SPI_PIO_CMD2_DUMMY_CYCLES_11 (11 << 12) 55 | #define SPI_PIO_CMD2_DUMMY_CYCLES_12 (12 << 12) 56 | #define SPI_PIO_CMD2_DUMMY_CYCLES_13 (13 << 12) 57 | #define SPI_PIO_CMD2_DUMMY_CYCLES_14 (14 << 12) 58 | #define SPI_PIO_CMD2_DUMMY_CYCLES_15 (15 << 12) 59 | #define SPI_PIO_CMD1_SHIFT 16 60 | #define SPI_PIO_CMD1_MASK (255 << 16) 61 | #define SPI_PIO_CMD2_SHIFT 24 62 | #define SPI_PIO_CMD2_MASK (255 << 24) 63 | 64 | #define SPI_CTRL1 (SPI_ADDR + 0x08) 65 | #define SPI_CTRL1_LATCH_DELAY_0 (0 << 0) 66 | #define SPI_CTRL1_LATCH_DELAY_1 (1 << 0) 67 | #define SPI_CTRL1_LATCH_DELAY_2 (2 << 0) 68 | #define SPI_CTRL1_LATCH_DELAY_3 (3 << 0) 69 | #define SPI_CTRL1_BUS_IDLE (1 << 8) 70 | 71 | #define SPI_CTRL2 (SPI_ADDR + 0x0c) 72 | #define SPI_CTRL2_DDR_ENABLE (1 << 1) 73 | 74 | #define SPI_WRITE_COUNT (SPI_ADDR + 0x10) 75 | #define SPI_READ_COUNT (SPI_ADDR + 0x14) 76 | #define SPI_RESET (SPI_ADDR + 0x18) 77 | #define SPI_STATUS (SPI_ADDR + 0x1c) 78 | #define SPI_DELAY1 (SPI_ADDR + 0x20) 79 | #define SPI_DELAY2 (SPI_ADDR + 0x24) 80 | #define SPI_DELAY3 (SPI_ADDR + 0x28) 81 | #define SPI_DELAY4 (SPI_ADDR + 0x2c) 82 | #define SPI_DELAY5 (SPI_ADDR + 0x30) 83 | #define SPI_DELAY6 (SPI_ADDR + 0x34) 84 | #define SPI_DELAY7 (SPI_ADDR + 0x38) 85 | #define SPI_DELAY8 (SPI_ADDR + 0x3c) 86 | #define SPI_PIO_CS1 (SPI_ADDR + 0x40) /* Same map as SPI_PIO_CS0 */ 87 | 88 | #define SPI_CTRL3 (SPI_ADDR + 0x44) 89 | #define SPI_CTRL3_CHANNEL1_MASK (1 << 8) 90 | #define SPI_CTRL3_CHANNEL2_MASK (1 << 9) 91 | #define SPI_CTRL3_CHANNEL3_MASK (1 << 10) 92 | #define SPI_CTRL3_CHANNEL4_MASK (1 << 11) 93 | #define SPI_CTRL3_CHANNEL1_IDLE (1 << 12) 94 | #define SPI_CTRL3_CHANNEL2_IDLE (1 << 13) 95 | #define SPI_CTRL3_CHANNEL3_IDLE (1 << 14) 96 | #define SPI_CTRL3_CHANNEL4_IDLE (1 << 15) 97 | 98 | /* Dedicated buffer for SPI data */ 99 | #define SPI_DATA ((void *)(SPI_ADDR + 0x800)) 100 | 101 | #endif /* __FV_SPI_H__ */ 102 | -------------------------------------------------------------------------------- /include/fernvale-usb.h: -------------------------------------------------------------------------------- 1 | #ifndef __FV_USB_H__ 2 | #define __FV_USB_H__ 3 | 4 | #define USB_CTRL_ADDR 0xa0900000 5 | 6 | #define USB_CTRL_FADDR (USB_CTRL_ADDR + 0x00) 7 | 8 | #define USB_CTRL_POWER (USB_CTRL_ADDR + 0x01) 9 | #define USB_CTRL_POWER_SUSPENAB (1 << 0) 10 | #define USB_CTRL_POWER_SUSPMODE (1 << 1) 11 | #define USB_CTRL_POWER_RESUME (1 << 2) 12 | #define USB_CTRL_POWER_RESET (1 << 3) 13 | #define USB_CTRL_POWER_SWRSTENAB (1 << 4) 14 | #define USB_CTRL_POWER_ISOUPDATE (1 << 7) 15 | 16 | #define USB_CTRL_INTRIN (USB_CTRL_ADDR + 0x02) 17 | #define USB_CTRL_INTRIN_EP0 (1 << 0) 18 | #define USB_CTRL_INTRIN_EP1_IN (1 << 1) 19 | #define USB_CTRL_INTRIN_EP2_IN (1 << 2) 20 | #define USB_CTRL_INTRIN_EP3_IN (1 << 3) 21 | #define USB_CTRL_INTRIN_EP4_IN (1 << 4) 22 | 23 | #define USB_CTRL_INTROUT (USB_CTRL_ADDR + 0x04) 24 | #define USB_CTRL_INTROUT_EP1_OUT (1 << 1) 25 | #define USB_CTRL_INTROUT_EP2_OUT (1 << 2) 26 | 27 | #define USB_CTRL_INTRUSB (USB_CTRL_ADDR + 0x06) 28 | #define USB_CTRL_INTRUSB_SUSPEND (1 << 0) 29 | #define USB_CTRL_INTRUSB_RESUME (1 << 1) 30 | #define USB_CTRL_INTRUSB_RESET (1 << 2) 31 | #define USB_CTRL_INTRUSB_SOF (1 << 3) 32 | #define USB_CTRL_INTRUSB_POWERDWN (1 << 4) 33 | 34 | /* IN interrupt enable */ 35 | #define USB_CTRL_INTRINE (USB_CTRL_ADDR + 0x07) 36 | #define USB_CTRL_INTRINE_EP0_ENABLE (1 << 0) 37 | #define USB_CTRL_INTRINE_EP1_IN_ENABLE (1 << 1) 38 | #define USB_CTRL_INTRINE_EP2_IN_ENABLE (1 << 2) 39 | #define USB_CTRL_INTRINE_EP3_IN_ENABLE (1 << 3) 40 | #define USB_CTRL_INTRINE_EP4_IN_ENABLE (1 << 4) 41 | 42 | #define USB_CTRL_INTROUTE (USB_CTRL_ADDR + 0x09) 43 | #define USB_CTRL_INTROUTE_EP1_OUT_ENABLE (1 << 1) 44 | #define USB_CTRL_INTROUTE_EP2_OUT_ENABLE (1 << 2) 45 | 46 | #define USB_CTRL_INTRUSBE (USB_CTRL_ADDR + 0x0b) 47 | #define USB_CTRL_INTRUSBE_SUSPEND_ENABLE (1 << 0) 48 | #define USB_CTRL_INTRUSBE_RESUME_ENABLE (1 << 1) 49 | #define USB_CTRL_INTRUSBE_RESET_ENABLE (1 << 2) 50 | #define USB_CTRL_INTRUSBE_SOF_ENABLE (1 << 3) 51 | #define USB_CTRL_INTRUSBE_POWERDWN_ENABLE (1 << 4) 52 | 53 | #define USB_CTRL_FRAME_COUNT1 (USB_CTRL_ADDR + 0x0c) 54 | #define USB_CTRL_FRAME_COUNT2 (USB_CTRL_ADDR + 0x0d) 55 | 56 | #define USB_CTRL_INDEX (USB_CTRL_ADDR + 0x0e) 57 | #define USB_CTRL_RSTCTRL (USB_CTRL_ADDR + 0x0f) 58 | 59 | #define USB_CTRL_EP_INMAXP (USB_CTRL_ADDR + 0x10) 60 | 61 | #define USB_CTRL_EP0_CSR (USB_CTRL_ADDR + 0x11) 62 | #define USB_CTRL_EP0_CSR_OUTPKTRDY (1 << 0) 63 | #define USB_CTRL_EP0_CSR_INPKTRDY (1 << 1) 64 | #define USB_CTRL_EP0_CSR_SENTSTALL (1 << 2) 65 | #define USB_CTRL_EP0_CSR_DATAEND (1 << 3) 66 | #define USB_CTRL_EP0_CSR_SETUPEND (1 << 4) 67 | #define USB_CTRL_EP0_CSR_SENDSTALL (1 << 5) 68 | #define USB_CTRL_EP0_CSR_SOUTPKTRDY (1 << 6) 69 | #define USB_CTRL_EP0_CSR_SSETUPEND (1 << 7) 70 | 71 | #define USB_CTRL_EP_INCSR1 (USB_CTRL_ADDR + 0x11) 72 | #define USB_CTRL_EP_INCSR1_INPKTRDY (1 << 0) 73 | #define USB_CTRL_EP_INCSR1_FIFONOTEMPTY (1 << 1) 74 | #define USB_CTRL_EP_INCSR1_UNDERRUN (1 << 2) 75 | #define USB_CTRL_EP_INCSR1_FLUSHFIFO (1 << 3) 76 | #define USB_CTRL_EP_INCSR1_SENDSTALL (1 << 4) 77 | #define USB_CTRL_EP_INCSR1_SENTSTALL (1 << 5) 78 | #define USB_CTRL_EP_INCSR1_CLRDATATOG (1 << 6) 79 | #define USB_CTRL_EP_INCSR1_ABORTPKT_ENABLE (1 << 7) 80 | 81 | #define USB_CTRL_EP_INCSR2 (USB_CTRL_ADDR + 0x12) 82 | #define USB_CTRL_EP_INCSR2_FRCDATATOG (1 << 3) 83 | #define USB_CTRL_EP_INCSR2_DMAENAB (1 << 4) 84 | #define USB_CTRL_EP_INCSR2_MODE (1 << 5) 85 | #define USB_CTRL_EP_INCSR2_ISO (1 << 6) 86 | #define USB_CTRL_EP_INCSR2_AUTOSET (1 << 7) 87 | 88 | #define USB_CTRL_EP_OUTMAXP (USB_CTRL_ADDR + 0x13) 89 | 90 | #define USB_CTRL_EP_OUTCSR1 (USB_CTRL_ADDR + 0x14) 91 | #define USB_CTRL_EP_OUTCSR1_RXPKTRDY (1 << 0) 92 | #define USB_CTRL_EP_OUTCSR1_FIFOFULL (1 << 1) 93 | #define USB_CTRL_EP_OUTCSR1_OVERRUN (1 << 2) 94 | #define USB_CTRL_EP_OUTCSR1_DATAERROR (1 << 3) 95 | #define USB_CTRL_EP_OUTCSR1_FLUSHFIFO (1 << 4) 96 | #define USB_CTRL_EP_OUTCSR1_SENDSTALL (1 << 5) 97 | #define USB_CTRL_EP_OUTCSR1_SENTSTALL (1 << 6) 98 | #define USB_CTRL_EP_OUTCSR1_CLRDTATOG (1 << 7) 99 | 100 | #define USB_CTRL_EP_OUTCSR2 (USB_CTRL_ADDR + 0x15) 101 | #define USB_CTRL_EP_OUTCSR2_DMAMODE (1 << 4) 102 | #define USB_CTRL_EP_OUTCSR2_DMAENAB (1 << 5) 103 | #define USB_CTRL_EP_OUTCSR2_ISO (1 << 6) 104 | #define USB_CTRL_EP_OUTCSR2_AUTOCLEAR (1 << 7) 105 | 106 | #define USB_CTRL_EP0_COUNT (USB_CTRL_ADDR + 0x16) 107 | 108 | #define USB_CTRL_EP_COUNT1 (USB_CTRL_ADDR + 0x16) 109 | 110 | #define USB_CTRL_EP_COUNT2 (USB_CTRL_ADDR + 0x17) 111 | 112 | #define USB_CTRL_EP0_FIFO_DB0 (USB_CTRL_ADDR + 0x20) 113 | #define USB_CTRL_EP0_FIFO_DB1 (USB_CTRL_ADDR + 0x21) 114 | #define USB_CTRL_EP0_FIFO_DB2 (USB_CTRL_ADDR + 0x22) 115 | #define USB_CTRL_EP0_FIFO_DB3 (USB_CTRL_ADDR + 0x23) 116 | 117 | #define USB_CTRL_EP1_FIFO_DB0 (USB_CTRL_ADDR + 0x24) 118 | #define USB_CTRL_EP1_FIFO_DB1 (USB_CTRL_ADDR + 0x25) 119 | #define USB_CTRL_EP1_FIFO_DB2 (USB_CTRL_ADDR + 0x26) 120 | #define USB_CTRL_EP1_FIFO_DB3 (USB_CTRL_ADDR + 0x27) 121 | 122 | #define USB_CTRL_EP2_FIFO_DB0 (USB_CTRL_ADDR + 0x28) 123 | #define USB_CTRL_EP2_FIFO_DB1 (USB_CTRL_ADDR + 0x29) 124 | #define USB_CTRL_EP2_FIFO_DB2 (USB_CTRL_ADDR + 0x2a) 125 | #define USB_CTRL_EP2_FIFO_DB3 (USB_CTRL_ADDR + 0x2b) 126 | 127 | #define USB_CTRL_EP3_FIFO_DB0 (USB_CTRL_ADDR + 0x2c) 128 | #define USB_CTRL_EP3_FIFO_DB1 (USB_CTRL_ADDR + 0x2d) 129 | #define USB_CTRL_EP3_FIFO_DB2 (USB_CTRL_ADDR + 0x2e) 130 | #define USB_CTRL_EP3_FIFO_DB3 (USB_CTRL_ADDR + 0x2f) 131 | 132 | #define USB_CTRL_EP4_FIFO_DB0 (USB_CTRL_ADDR + 0x30) 133 | #define USB_CTRL_EP4_FIFO_DB1 (USB_CTRL_ADDR + 0x31) 134 | #define USB_CTRL_EP4_FIFO_DB2 (USB_CTRL_ADDR + 0x32) 135 | #define USB_CTRL_EP4_FIFO_DB3 (USB_CTRL_ADDR + 0x33) 136 | 137 | #define USB_CTRL_CON (USB_CTRL_ADDR + 0x240) 138 | /* Enable 1.5k pullup on D+ pin */ 139 | #define USB_CTRL_CON_DPPULLUP (1 << 0) 140 | /* Enable 1.5k pullup on D- pin */ 141 | #define USB_CTRL_CON_DNPULLUP (1 << 1) 142 | /* Don't issue a DMA request when a null packet is received */ 143 | #define USB_CTRL_CON_NULLPKT_FIX (1 << 5) 144 | 145 | #endif /* __FV_USB_H__ */ 146 | -------------------------------------------------------------------------------- /include/gnu/stubs-soft.h: -------------------------------------------------------------------------------- 1 | /* This file is automatically generated. 2 | It defines a symbol `__stub_FUNCTION' for each function 3 | in the C library which is a stub, meaning it will fail 4 | every time called, usually setting errno to ENOSYS. */ 5 | 6 | #ifdef _LIBC 7 | # error Applications may not define the macro _LIBC 8 | #endif 9 | 10 | #define __stub_chflags 11 | #define __stub_create_module 12 | #define __stub_fattach 13 | #define __stub_fchflags 14 | #define __stub_fdetach 15 | #define __stub_get_kernel_syms 16 | #define __stub_getmsg 17 | #define __stub_getpmsg 18 | #define __stub_gtty 19 | #define __stub_lchmod 20 | #define __stub_putmsg 21 | #define __stub_putpmsg 22 | #define __stub_query_module 23 | #define __stub_revoke 24 | #define __stub_setlogin 25 | #define __stub_sigreturn 26 | #define __stub_sstk 27 | #define __stub_stty 28 | -------------------------------------------------------------------------------- /include/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef __IRQ_H__ 2 | #define __IRQ_H__ 3 | 4 | enum irq_number { 5 | irq_unk_0, 6 | irq_unk_1, 7 | irq_unk_2, 8 | irq_unk_3, 9 | irq_unk_4, 10 | irq_unk_5, 11 | irq_unk_6, 12 | irq_unk_7, 13 | irq_unk_8, 14 | irq_unk_9, 15 | irq_unk_10, 16 | irq_unk_11, 17 | irq_unk_12, 18 | irq_unk_13, 19 | irq_unk_14, 20 | irq_uart1, 21 | irq_unk_16, 22 | irq_uart2, 23 | irq_unk_18, 24 | irq_unk_19, 25 | irq_unk_20, 26 | irq_unk_21, 27 | irq_unk_22, 28 | irq_unk_23, 29 | irq_unk_24, 30 | irq_unk_25, 31 | irq_unk_26, 32 | irq_unk_27, 33 | irq_unk_28, 34 | irq_unk_29, 35 | irq_unk_30, 36 | irq_unk_31, 37 | irq_unk_32, 38 | irq_unk_33, 39 | irq_unk_34, 40 | irq_unk_35, 41 | irq_unk_36, 42 | irq_unk_37, 43 | irq_unk_38, 44 | irq_unk_39, 45 | irq_unk_40, 46 | irq_unk_41, 47 | irq_unk_42, 48 | irq_unk_43, 49 | irq_unk_44, 50 | irq_unk_45, 51 | irq_unk_46, 52 | irq_unk_47, 53 | __irq_max__, 54 | }; 55 | 56 | int irq_init(void); 57 | int fiq_init(void); 58 | int irq_enable(enum irq_number irq_num); 59 | int irq_disable(enum irq_number irq_num); 60 | void irq_acknowledge(enum irq_number irq_num); 61 | void irq_mask_acknowledge(enum irq_number irq_num); 62 | void irq_dispatch(void); 63 | void irq_stimulate(enum irq_number irq_num); 64 | void irq_stimulate_reset(enum irq_number irq_num); 65 | 66 | void irq_register_handler(enum irq_number irq_num, 67 | void (*handler)(enum irq_number irq_num, void *opaque), 68 | void *opaque); 69 | 70 | #define IRQ_BASE (0xa0060000) 71 | #define IRQ_MASK_OFF 0x00 /* IRQ mask (enabled/disabled) */ 72 | #define IRQ_SENSE_OFF 0x60 /* IRQ sensitivity (edge vs level) */ 73 | #define IRQ_STIM_OFF 0xc0 /* IRQ "stimulate" (for debug) */ 74 | #define IRQ_STATUS_OFF 0x100 /* IRQ status (IRQ firing or not) */ 75 | #define FIQ_STATUS_OFF 0x140 /* FIQ status (FIQ firing or not) */ 76 | #define IRQ_ACK_OFF 0x160 /* IRQ acknowledge (write a 1 to acknowledge) */ 77 | #define FIQ_SOURCE_OFF 0x180 /* IRQ number used as FIQ */ 78 | 79 | #define IRQ_SET 0x20 /* Offset from OFF for "SET" behaviour */ 80 | #define IRQ_CLR 0x40 /* Offset from OFF for "CLR" behaviour */ 81 | 82 | #define IRQ_NUM_ADJ(x) (((x) > 32) ? 4 : 0) /* Offset for IRQs > 32 */ 83 | 84 | #endif /* __IRQ_H__ */ 85 | -------------------------------------------------------------------------------- /include/lcd.h: -------------------------------------------------------------------------------- 1 | #ifndef __LCD_H__ 2 | #define __LCD_H__ 3 | 4 | typedef uint16_t pixel_t; 5 | 6 | /* Current LCD is rgb565, but this function can change for different panels */ 7 | static inline pixel_t rgb(unsigned r, unsigned g, unsigned b) 8 | { 9 | uint16_t c = (((r >> 3) & 0x1f) << 11) | 10 | (((g >> 2) & 0x3f) << 5) | 11 | (((b >> 3) & 0x1f) ); 12 | //c = ((c >> 8) & 0x00ff) | ((c << 8) & 0xff00); 13 | return c; 14 | } 15 | 16 | int lcd_init(void); 17 | int lcd_run(void); 18 | int lcd_stop(void); 19 | 20 | pixel_t *lcd_fb(void); 21 | uint32_t lcd_width(void); 22 | uint32_t lcd_height(void); 23 | uint32_t lcd_bpp(void); 24 | 25 | void lcd_addpixel(pixel_t px); 26 | 27 | #endif /* __LCD_H__ */ 28 | -------------------------------------------------------------------------------- /include/memio.h: -------------------------------------------------------------------------------- 1 | #ifndef __FV_MEMIO_H__ 2 | #define __FV_MEMIO_H__ 3 | #include 4 | 5 | static inline void writeb(uint8_t value, uint32_t addr) 6 | { 7 | *((volatile uint8_t *)addr) = value; 8 | } 9 | 10 | static inline uint8_t readb(uint32_t addr) 11 | { 12 | return *(volatile uint8_t *)addr; 13 | } 14 | 15 | static inline void writew(uint16_t value, uint32_t addr) 16 | { 17 | *((volatile uint16_t *)addr) = value; 18 | } 19 | 20 | static inline uint16_t readw(uint32_t addr) 21 | { 22 | return *(volatile uint16_t *)addr; 23 | } 24 | 25 | static inline void writel(uint32_t value, uint32_t addr) 26 | { 27 | *((volatile uint32_t *)addr) = value; 28 | } 29 | 30 | static inline uint32_t readl(uint32_t addr) 31 | { 32 | return *(volatile uint32_t *)addr; 33 | } 34 | 35 | #endif /* __FV_MEMIO_H__ */ 36 | -------------------------------------------------------------------------------- /include/printf.h: -------------------------------------------------------------------------------- 1 | #ifndef __PRINTF_H__ 2 | #define __PRINTF_H__ 3 | 4 | int printf(const char *fmt, ...); 5 | 6 | #endif /* __PRINTF_H__ */ 7 | -------------------------------------------------------------------------------- /include/scriptic.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCRIPTIC_H__ 2 | #define __SCRIPTIC_H__ 3 | 4 | #define sc_end_cmd 0 5 | #define sc_read32_cmd 1 6 | #define sc_write32_cmd 2 7 | #define sc_read16_cmd 3 8 | #define sc_write16_cmd 4 9 | #define sc_call_cmd 5 10 | #define sc_usleep_cmd 6 11 | 12 | #define sc_header_size (4 * 2) 13 | #define sc_end_size (sc_header_size + 0) 14 | #define sc_read32_size (sc_header_size + 4 * 3) 15 | #define sc_write32_size (sc_header_size + 4 * 3) 16 | #define sc_read16_size (sc_header_size + 4 * 2 + 1 * 4) 17 | #define sc_write16_size (sc_header_size + 4 * 2 + 1 * 4) 18 | #define sc_call_size (sc_header_size + 4 * 2) 19 | #define sc_usleep_size (sc_header_size + 4 * 1) 20 | 21 | #ifdef __ASSEMBLY__ 22 | 23 | .macro sc_header cmd 24 | @cmdindex=@cmdindex+1 25 | .long \cmd 26 | .long 0 @cmdindex 27 | .endm 28 | 29 | .macro sc_end 30 | sc_header sc_end_cmd 31 | .endm 32 | 33 | .macro sc_read32 match, mask, addr 34 | sc_header sc_read32_cmd 35 | .long \match 36 | .long \mask 37 | .long \addr 38 | .endm 39 | 40 | .macro sc_write32 value, mask, addr 41 | sc_header sc_write32_cmd 42 | .long \value 43 | .long \mask 44 | .long \addr 45 | .endm 46 | 47 | .macro sc_read16 match, mask, addr 48 | sc_header sc_read16_cmd 49 | .short \match 50 | .short \mask 51 | .long \addr 52 | .endm 53 | 54 | .macro sc_write16 value, mask, addr 55 | sc_header sc_write16_cmd 56 | .short \value 57 | .short \mask 58 | .long \addr 59 | .endm 60 | 61 | .macro sc_call func, arg 62 | sc_header sc_call_cmd 63 | .long \func 64 | .long \arg 65 | .endm 66 | 67 | .macro sc_usleep microsecs 68 | sc_header sc_usleep_cmd 69 | .long \microsecs 70 | .endm 71 | 72 | .macro sc_new name, major, minor, rev 73 | .align 4 74 | .global \name 75 | @cmdindex=0 // Reset command index counter variable 76 | \name: 77 | 1: 78 | .asciz "\name" 79 | 2: 80 | .iflt 16 - (2b - 1b) 81 | .error "Name too long (16-bytes max)" 82 | .endif 83 | 84 | // Zero-pad 85 | .ifgt 16 - (2b - 1b) 86 | .zero 16 - (2b - 1b) 87 | .endif 88 | 89 | .byte \major // ver_major 90 | .byte \minor // ver_minor 91 | .short \rev // ver_rev 92 | .long 0 // command_count 93 | // Commands will follow in RAM 94 | .endm 95 | 96 | #else /* ! __ASSEMBLY__ */ 97 | 98 | #include 99 | 100 | /* Header prefixed in all commands */ 101 | struct scriptic_header { 102 | uint32_t command; 103 | uint32_t index; 104 | } __attribute__((__packed__)); 105 | 106 | /* Stop execution */ 107 | struct scriptic_end { 108 | struct scriptic_header header; 109 | } __attribute__((__packed__)); 110 | 111 | /* Read 32-bit value (and optionally wait for a value) */ 112 | struct scriptic_read32 { 113 | struct scriptic_header header; 114 | uint32_t match; /* Value to match */ 115 | uint32_t mask; /* Mask for bits to match */ 116 | uint32_t addr; /* Address to read from */ 117 | } __attribute__((__packed__)); 118 | 119 | /* Write a 32-bit value to an address */ 120 | struct scriptic_write32 { 121 | struct scriptic_header header; 122 | uint32_t value; /* Value to write */ 123 | uint32_t mask; /* Mask for bits to write */ 124 | uint32_t addr; /* Address to write to */ 125 | } __attribute__((__packed__)); 126 | 127 | /* Read 16-bit value (and optionally wait for a value) */ 128 | struct scriptic_read16 { 129 | struct scriptic_header header; 130 | uint16_t match; /* Value to match */ 131 | uint16_t mask; /* Mask for bits to match */ 132 | uint32_t addr; /* Address to read from */ 133 | } __attribute__((__packed__)); 134 | 135 | /* Write a 16-bit value to an address */ 136 | struct scriptic_write16 { 137 | struct scriptic_header header; 138 | uint16_t value; /* Value to write */ 139 | uint16_t mask; /* Mask for bits to write */ 140 | uint32_t addr; /* Address to write to */ 141 | } __attribute__((__packed__)); 142 | 143 | /* Call a function repeatedly and wait for it to return true */ 144 | struct scriptic_call { 145 | struct scriptic_header header; 146 | int (*func)(void *arg); /* Function to call */ 147 | void *opaque; /* Arg to pass */ 148 | } __attribute__((__packed__)); 149 | 150 | /* Sleep for a given number of microseconds */ 151 | struct scriptic_usleep { 152 | struct scriptic_header header; 153 | uint32_t usecs; /* Number of microseconds */ 154 | } __attribute__((__packed__)); 155 | 156 | union scriptic_command { 157 | struct scriptic_header header; 158 | struct scriptic_end end; 159 | struct scriptic_read32 read32; 160 | struct scriptic_write32 write32; 161 | struct scriptic_read16 read16; 162 | struct scriptic_write16 write16; 163 | struct scriptic_call call; 164 | struct scriptic_usleep usleep; 165 | }; 166 | 167 | struct scriptic { 168 | const char name[16]; 169 | uint8_t ver_major; 170 | uint8_t ver_minor; 171 | uint16_t ver_rev; 172 | uint32_t command_count; 173 | } __attribute__((__packed__)); 174 | 175 | int scriptic_execute(const struct scriptic *script); 176 | const struct scriptic *scriptic_get(const char *name); 177 | int scriptic_run(const char *name); 178 | 179 | #endif /* __ASSEMBLY__ */ 180 | 181 | #endif /* __SCRIPTIC_H__ */ 182 | -------------------------------------------------------------------------------- /include/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef __SERIAL_H__ 2 | #define __SERIAL_H__ 3 | 4 | #include 5 | 6 | int serial_putc(uint8_t c); 7 | int serial_puts(const void *s); 8 | void serial_puth(uint32_t hex, int digits); /* Put hex */ 9 | void serial_write(const void *d, int bytes); 10 | 11 | uint8_t serial_getc(void); 12 | int serial_available(void); 13 | int serial_print_hex(const void *bfr, int count); 14 | int serial_read(void *data, int bytes); 15 | 16 | void serial_init(void); 17 | 18 | #endif /* __SERIAL_H__ */ 19 | -------------------------------------------------------------------------------- /include/spi.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __SPI_H__ 3 | #define __SPI_H__ 4 | 5 | int spi_cmd_txrx(uint8_t tx_size, uint8_t rx_size, 6 | uint8_t *tx_buf, uint8_t *rx_buf); 7 | 8 | #endif /* __SPI_H__ */ 9 | -------------------------------------------------------------------------------- /include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_H__ 2 | #define __UTILS_H__ 3 | #include 4 | 5 | # define do_div(n,base) ({ \ 6 | uint32_t __base = (base); \ 7 | uint32_t __rem; \ 8 | (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ 9 | if (((n) >> 32) == 0) { \ 10 | __rem = (uint32_t)(n) % __base; \ 11 | (n) = (uint32_t)(n) / __base; \ 12 | } else \ 13 | __rem = __div64_32(&(n), __base); \ 14 | __rem; \ 15 | }) 16 | 17 | uint32_t _udiv64(uint64_t n, uint32_t d); 18 | uint32_t __div64_32(uint64_t *n, uint32_t base); 19 | 20 | #endif /* __UTILS_H__ */ 21 | -------------------------------------------------------------------------------- /irq.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "serial.h" 3 | #include "printf.h" 4 | #include "irq.h" 5 | #include "memio.h" 6 | 7 | static struct { 8 | void (*handler)(enum irq_number irq_num, void *opaque); 9 | void *opaque; 10 | } handlers[__irq_max__]; 11 | 12 | int irq_init(void) 13 | { 14 | register int var; 15 | 16 | /* Acknowledge all interrupts */ 17 | writel(0xffffffff, IRQ_BASE + IRQ_MASK_OFF + IRQ_NUM_ADJ(0)); 18 | writel(0xffffffff, IRQ_BASE + IRQ_MASK_OFF + IRQ_NUM_ADJ(32)); 19 | 20 | asm volatile ("mrs %0, cpsr":"=r" (var)); 21 | if (!(var & 0x80)) { 22 | serial_puts("Interrupts already enabled\n"); 23 | return -1; 24 | } 25 | 26 | serial_puts("Interrupts were disabled. Re-enabling...\n"); 27 | var &= ~0x80; 28 | var |= 0x40; 29 | var &= ~0x1f; 30 | var |= 0x10; 31 | asm volatile ("msr cpsr, %0":"=r" (var)); 32 | 33 | return 0; 34 | } 35 | 36 | int fiq_init(void) 37 | { 38 | serial_puts("FIQs compiled out\n"); 39 | return -1; 40 | /* 41 | register int var; 42 | asm volatile ("mrs %0, cpsr":"=r" (var)); 43 | if (!(var & 0x40)) { 44 | serial_puts("FIQ already enabled\n"); 45 | return -1; 46 | } 47 | 48 | serial_puts("FIQ was disabled. Re-enabling...\n"); 49 | var &= ~0x40; 50 | asm volatile ("msr cpsr, %0":"=r" (var)); 51 | 52 | return 0; 53 | */ 54 | } 55 | 56 | int irq_enable(enum irq_number irq_num) 57 | { 58 | uint32_t reg = IRQ_BASE + IRQ_MASK_OFF + IRQ_CLR + IRQ_NUM_ADJ(irq_num); 59 | if (irq_num >= __irq_max__) 60 | return -1; 61 | 62 | writel(1 << (irq_num & 31), reg); 63 | return 0; 64 | } 65 | 66 | int irq_disable(enum irq_number irq_num) 67 | { 68 | uint32_t reg = IRQ_BASE + IRQ_MASK_OFF + IRQ_SET + IRQ_NUM_ADJ(irq_num); 69 | 70 | if (irq_num >= __irq_max__) 71 | return -1; 72 | 73 | writel(1 << (irq_num & 31), reg); 74 | return 0; 75 | } 76 | 77 | void irq_stimulate(enum irq_number irq_num) 78 | { 79 | uint32_t reg = IRQ_BASE + IRQ_STIM_OFF + IRQ_SET + IRQ_NUM_ADJ(irq_num); 80 | writel(1 << (irq_num & 31), reg); 81 | } 82 | 83 | void irq_stimulate_reset(enum irq_number irq_num) 84 | { 85 | uint32_t reg = IRQ_BASE + IRQ_STIM_OFF + IRQ_CLR + IRQ_NUM_ADJ(irq_num); 86 | writel(1 << (irq_num & 31), reg); 87 | } 88 | 89 | void irq_acknowledge(enum irq_number irq_num) 90 | { 91 | uint32_t reg = IRQ_BASE + IRQ_ACK_OFF + IRQ_NUM_ADJ(irq_num); 92 | 93 | if (irq_num >= __irq_max__) 94 | return; 95 | 96 | writel(1 << (irq_num & 31), reg); 97 | return; 98 | } 99 | 100 | void irq_mask_acknowledge(enum irq_number irq_num) 101 | { 102 | irq_disable(irq_num); 103 | irq_acknowledge(irq_num); 104 | } 105 | 106 | void irq_register_handler(enum irq_number irq_num, 107 | void (*handler)(enum irq_number irq_num, void *opaque), 108 | void *opaque) 109 | { 110 | if (irq_num >= __irq_max__) 111 | return; 112 | handlers[irq_num].handler = handler; 113 | handlers[irq_num].opaque = opaque; 114 | } 115 | 116 | static void irq_dispatch_one(enum irq_number irq_num) 117 | { 118 | if (handlers[irq_num].handler) 119 | handlers[irq_num].handler(irq_num, handlers[irq_num].opaque); 120 | else 121 | printf("Unhandled IRQ: %d\n", irq_num); 122 | irq_acknowledge(irq_num); 123 | } 124 | 125 | void irq_dispatch(void) 126 | { 127 | uint32_t reg; 128 | uint32_t val; 129 | int i; 130 | 131 | printf("Dispatching IRQs...\n"); 132 | reg = IRQ_BASE + IRQ_STATUS_OFF; 133 | val = readl(reg); 134 | printf("Lower Mask: 0x%08"PRIx32"\n", val); 135 | 136 | for (i = 0; i < 32; i++) 137 | if (val & (1 << i)) 138 | irq_dispatch_one(i); 139 | 140 | reg += IRQ_BASE + IRQ_STATUS_OFF + 4; 141 | val = readl(reg); 142 | printf("Upper Mask: 0x%08"PRIx32"\n", val); 143 | for (i = 0; i < (__irq_max__ - 32); i++) 144 | if (val & (1 << i)) 145 | irq_dispatch_one(32 + i); 146 | 147 | printf("Done dispatch\n"); 148 | } 149 | -------------------------------------------------------------------------------- /irqasm.S: -------------------------------------------------------------------------------- 1 | #define MODE_MASK 0x0000001f /* Bits 0-4: Mode bits */ 2 | # define USR26_MODE 0x00000000 /* 26-bit User mode */ 3 | # define FIQ26_MODE 0x00000001 /* 26-bit FIQ mode */ 4 | # define IRQ26_MODE 0x00000002 /* 26-bit IRQ mode */ 5 | # define SVC26_MODE 0x00000003 /* 26-bit Supervisor mode */ 6 | # define MODE32_BIT 0x00000010 /* Bit 4: 32-bit mode */ 7 | # define USR_MODE 0x00000010 /* 32-bit User mode */ 8 | # define FIQ_MODE 0x00000011 /* 32-bit FIQ mode */ 9 | # define IRQ_MODE 0x00000012 /* 32-bit IRQ mode */ 10 | # define SVC_MODE 0x00000013 /* 32-bit Supervisor mode */ 11 | # define ABT_MODE 0x00000017 /* 32-bit Abort mode */ 12 | # define UND_MODE 0x0000001b /* 32-bit Undefined mode */ 13 | # define SYSTEM_MODE 0x0000001f /* 32-bit System mode */ 14 | #define PSR_T_BIT 0x00000020 /* Bit 5: Thumb state */ 15 | #define PSR_F_BIT 0x00000040 /* Bit 6: FIQ disable */ 16 | #define PSR_I_BIT 0x00000080 /* Bit 7: IRQ disable */ 17 | /* Bits 8-23: Reserved */ 18 | #define PSR_J_BIT 0x01000000 /* Bit 24: Jazelle state bit */ 19 | /* Bits 25-26: Reserved */ 20 | #define PSR_Q_BIT 0x08000000 /* Bit 27: Sticky overflow */ 21 | #define PSR_V_BIT 0x10000000 /* Bit 28: Overflow */ 22 | #define PSR_C_BIT 0x20000000 /* Bit 29: Carry/Borrow/Extend */ 23 | #define PSR_Z_BIT 0x40000000 /* Bit 30: Zero */ 24 | #define PSR_N_BIT 0x80000000 /* Bit 31: Negative/Less than */ 25 | 26 | /* CR1 bits (CP#15 CR1) */ 27 | 28 | #define CR_M 0x00000001 /* MMU enable */ 29 | #define CR_A 0x00000002 /* Alignment abort enable */ 30 | #define CR_C 0x00000004 /* Dcache enable */ 31 | #define CR_W 0x00000008 /* Write buffer enable */ 32 | #define CR_P 0x00000010 /* 32-bit exception handler */ 33 | #define CR_D 0x00000020 /* 32-bit data address range */ 34 | #define CR_L 0x00000040 /* Implementation defined */ 35 | #define CR_B 0x00000080 /* Big endian */ 36 | #define CR_S 0x00000100 /* System MMU protection */ 37 | #define CR_R 0x00000200 /* ROM MMU protection */ 38 | #define CR_F 0x00000400 /* Implementation defined */ 39 | #define CR_Z 0x00000800 /* Implementation defined */ 40 | #define CR_I 0x00001000 /* Icache enable */ 41 | #define CR_V 0x00002000 /* Vectors relocated to 0xffff0000 */ 42 | #define CR_RR 0x00004000 /* Round Robin cache replacement */ 43 | #define CR_L4 0x00008000 /* LDR pc can set T bit */ 44 | #define CR_DT 0x00010000 45 | #define CR_IT 0x00040000 46 | #define CR_ST 0x00080000 47 | #define CR_FI 0x00200000 /* Fast interrupt (lower latency mode) */ 48 | #define CR_U 0x00400000 /* Unaligned access operation */ 49 | #define CR_XP 0x00800000 /* Extended page tables */ 50 | #define CR_VE 0x01000000 /* Vectored interrupts */ 51 | 52 | #define REG_R0 (0) 53 | #define REG_R1 (1) 54 | #define REG_R2 (2) 55 | #define REG_R3 (3) 56 | #define REG_R4 (4) 57 | #define REG_R5 (5) 58 | #define REG_R6 (6) 59 | #define REG_R7 (7) 60 | #define REG_R8 (8) 61 | #define REG_R9 (9) 62 | #define REG_R10 (10) 63 | #define REG_R11 (11) 64 | #define REG_R12 (12) 65 | #define REG_R13 (13) 66 | #define REG_R14 (14) 67 | #define REG_R15 (15) 68 | #define REG_CPSR (16) 69 | 70 | #define XCPTCONTEXT_REGS (17) 71 | #define XCPTCONTEXT_SIZE (4 * XCPTCONTEXT_REGS) 72 | 73 | #define REG_A1 REG_R0 74 | #define REG_A2 REG_R1 75 | #define REG_A3 REG_R2 76 | #define REG_A4 REG_R3 77 | #define REG_V1 REG_R4 78 | #define REG_V2 REG_R5 79 | #define REG_V3 REG_R6 80 | #define REG_V4 REG_R7 81 | #define REG_V5 REG_R8 82 | #define REG_V6 REG_R9 83 | #define REG_V7 REG_R10 84 | #define REG_SB REG_R9 85 | #define REG_SL REG_R10 86 | #define REG_FP REG_R11 87 | #define REG_IP REG_R12 88 | #define REG_SP REG_R13 89 | #define REG_LR REG_R14 90 | #define REG_PC REG_R15 91 | 92 | .section data 93 | g_irqtmp: 94 | .word 0 /* Saved lr */ 95 | .word 0 /* Saved spsr */ 96 | g_undeftmp: 97 | .word 0 /* Saved lr */ 98 | .word 0 /* Saved spsr */ 99 | g_aborttmp: 100 | .word 0 /* Saved lr */ 101 | .word 0 /* Saved spsr */ 102 | 103 | .section text 104 | .global irq_handler 105 | 106 | irq_handler: 107 | /* On entry, we are in IRQ mode. We are free to use 108 | * the IRQ mode r13 and r14. 109 | */ 110 | ldr r13, .Lirqtmp 111 | sub lr, lr, #4 112 | str lr, [r13] @ save lr_IRQ 113 | mrs lr, spsr 114 | str lr, [r13, #4] @ save spsr_IRQ 115 | 116 | /* Then switch back to SVC mode */ 117 | 118 | bic lr, lr, #MODE_MASK /* Keep F and T bits */ 119 | orr lr, lr, #(SVC_MODE | PSR_I_BIT) 120 | msr cpsr_c, lr /* Switch to SVC mode */ 121 | 122 | /* Create a context structure. First set aside a stack frame 123 | * and store r0-r12 into the frame. 124 | */ 125 | 126 | sub sp, sp, #XCPTCONTEXT_SIZE 127 | stmia sp, {r0-r12} /* Save the SVC mode regs */ 128 | 129 | /* Get the correct values of r13(sp) and r14(lr) in r1 and r2 */ 130 | 131 | add r1, sp, #XCPTCONTEXT_SIZE 132 | mov r2, r14 133 | 134 | /* Get the values for r15(pc) and CPSR in r3 and r4 */ 135 | 136 | ldr r0, .Lirqtmp /* Points to temp storage */ 137 | ldmia r0, {r3, r4} /* Recover r1=lr_IRQ, r2=spsr_IRQ */ 138 | 139 | add r0, sp, #(4*REG_SP) /* Offset to pc, cpsr storage */ 140 | stmia r0, {r1-r4} 141 | 142 | /* Then call the IRQ handler with interrupts disabled. */ 143 | 144 | mov fp, #0 /* Init frame pointer */ 145 | mov r0, sp /* Get r0=xcp */ 146 | 147 | #if CONFIG_ARCH_INTERRUPTSTACK > 3 148 | ldr sp, .Lirqstackbase /* SP = interrupt stack base */ 149 | str r0, [sp] /* Save the user stack pointer */ 150 | bl irq_handler_c /* Call the handler */ 151 | ldr sp, [sp] /* Restore the user stack pointer */ 152 | #else 153 | bl irq_handler_c /* Call the handler */ 154 | 155 | /* Restore the CPSR, SVC mode registers and return */ 156 | .Lnoirqset: 157 | ldr r0, [sp, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */ 158 | msr spsr, r0 159 | #endif 160 | ldmia sp, {r0-r15}^ /* Return */ 161 | 162 | .Lirqtmp: 163 | .word g_irqtmp 164 | #if CONFIG_ARCH_INTERRUPTSTACK > 3 165 | .Lirqstackbase: 166 | .word g_intstackbase 167 | #endif 168 | .size irq_handler, . - irq_handler 169 | .align 5 170 | 171 | 172 | 173 | 174 | .globl swi_handler 175 | .type swi_handler, %function 176 | swi_handler: 177 | 178 | /* Create a context structure. First set aside a stack frame 179 | * and store r0-r12 into the frame. 180 | */ 181 | 182 | sub sp, sp, #XCPTCONTEXT_SIZE 183 | stmia sp, {r0-r12} /* Save the SVC mode regs */ 184 | 185 | /* Get the correct values of r13(sp), r14(lr), r15(pc) 186 | * and CPSR in r1-r4 */ 187 | 188 | add r1, sp, #XCPTCONTEXT_SIZE 189 | mov r2, r14 /* R14 is altered on return from SWI */ 190 | mov r3, r14 /* Save r14 as the PC as well */ 191 | mrs r4, spsr /* Get the saved CPSR */ 192 | 193 | add r0, sp, #(4*REG_SP) /* Offset to pc, cpsr storage */ 194 | stmia r0, {r1-r4} 195 | 196 | /* Then call the SWI handler with interrupts disabled. 197 | * void up_syscall(struct xcptcontext *xcp) 198 | */ 199 | 200 | mov fp, #0 /* Init frame pointer */ 201 | mov r0, sp /* Get r0=xcp */ 202 | /*bl swi_handler_c*/ /* Call the handler */ 203 | 204 | /* Restore the CPSR, SVC mode registers and return */ 205 | 206 | ldr r0, [sp, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */ 207 | msr spsr, r0 208 | ldmia sp, {r0-r15}^ /* Return */ 209 | .size swi_handler, . - swi_handler 210 | 211 | .align 5 212 | 213 | -------------------------------------------------------------------------------- /lcd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "memio.h" 4 | #include "printf.h" 5 | #include "fernvale-lcd.h" 6 | #include "fernvale-gpio.h" 7 | #include "fernvale-clockgate.h" 8 | #include "lcd.h" 9 | 10 | static pixel_t *fb = (pixel_t *)0x40000; 11 | static const uint32_t fb_height = 320; 12 | static const uint32_t fb_width = 240; 13 | static const uint32_t fb_bpp = 2; 14 | 15 | #define LCD_FORMAT (0 \ 16 | | LCD_AUTOCOPY_CTRL_FORMAT_PAD_MSB \ 17 | | LCD_AUTOCOPY_CTRL_FORMAT_RGB565 \ 18 | | LCD_AUTOCOPY_CTRL_FORMAT_IFACE_9BIT \ 19 | ) 20 | 21 | #define lcd_cmd(_cmd_) writew(_cmd_, LCD_PAR0_CMD_PORT_REG) 22 | #define lcd_dat(_dat_) writew(_dat_, LCD_PAR0_DAT_PORT_REG) 23 | 24 | /* Note these don't flush the DMA, you have to do this yourself 25 | * explicitly later on. 26 | * [slot] is the order to execute. 27 | */ 28 | enum lcd_slot_type { 29 | SLOT_DATA = 0, 30 | SLOT_CMD = 0x800000, 31 | }; 32 | 33 | static void lcd_slot(enum lcd_slot_type type, uint16_t cmd, uint8_t slot) 34 | { 35 | writel(cmd | type, LCD_CMD_LIST_ADDR + (slot * 4)); 36 | } 37 | 38 | static void lcd_setup_gpio(void) 39 | { 40 | /* LPCE0, LPTE0, LPRSTB */ 41 | writel(readl(GPIO_CTRL_MODE5) & ~(GPIO_CTRL_MODE5_IO40_MASK | 42 | GPIO_CTRL_MODE5_IO46_MASK | 43 | GPIO_CTRL_MODE5_IO45_MASK), 44 | GPIO_CTRL_MODE5); 45 | writel(readl(GPIO_CTRL_MODE5) | (GPIO_CTRL_MODE5_IO40_LPCE0B | 46 | GPIO_CTRL_MODE5_IO45_LPTE0 | 47 | GPIO_CTRL_MODE5_IO46_LPRSTB), 48 | GPIO_CTRL_MODE5); 49 | 50 | /* NLD0-4, LWRB, LRDB, LPA0 */ 51 | writel(readl(GPIO_CTRL_MODE4) & ~(GPIO_CTRL_MODE4_IO32_MASK | 52 | GPIO_CTRL_MODE4_IO33_MASK | 53 | GPIO_CTRL_MODE4_IO34_MASK | 54 | GPIO_CTRL_MODE4_IO35_MASK | 55 | GPIO_CTRL_MODE4_IO36_MASK | 56 | GPIO_CTRL_MODE4_IO37_MASK | 57 | GPIO_CTRL_MODE4_IO38_MASK | 58 | GPIO_CTRL_MODE4_IO39_MASK), 59 | GPIO_CTRL_MODE4); 60 | writel(readl(GPIO_CTRL_MODE4) | (GPIO_CTRL_MODE4_IO32_NLD4 | 61 | GPIO_CTRL_MODE4_IO33_NLD3 | 62 | GPIO_CTRL_MODE4_IO34_NLD2 | 63 | GPIO_CTRL_MODE4_IO35_NLD1 | 64 | GPIO_CTRL_MODE4_IO36_NLD0 | 65 | GPIO_CTRL_MODE4_IO37_LWRB | 66 | GPIO_CTRL_MODE4_IO38_LRDB | 67 | GPIO_CTRL_MODE4_IO39_LPA0), 68 | GPIO_CTRL_MODE4); 69 | 70 | /* NLD5-8 */ 71 | writel(readl(GPIO_CTRL_MODE3) & ~(GPIO_CTRL_MODE3_IO28_MASK | 72 | GPIO_CTRL_MODE3_IO29_MASK | 73 | GPIO_CTRL_MODE3_IO30_MASK | 74 | GPIO_CTRL_MODE3_IO31_MASK), 75 | GPIO_CTRL_MODE3); 76 | writel(readl(GPIO_CTRL_MODE3) | (GPIO_CTRL_MODE3_IO28_NLD8 | 77 | GPIO_CTRL_MODE3_IO29_NLD7 | 78 | GPIO_CTRL_MODE3_IO30_NLD6 | 79 | GPIO_CTRL_MODE3_IO31_NLD5), 80 | GPIO_CTRL_MODE3); 81 | } 82 | 83 | static int lcd_setup(void) 84 | { 85 | lcd_setup_gpio(); 86 | 87 | /* Power up the LCD block */ 88 | writel(CLKGATE_CTL0_LCD, CLKGATE_SYS_CTL0_CLR); 89 | 90 | _msleep(1); 91 | 92 | /* execute setup command 93 | * we're on CS0 94 | * our internal bus period is 166 MHz, or 6.25ns 95 | * write cycle = 66ns = 11 cycles - 1 = 10 96 | * write c22write su (tcs) = 15ns = 3 cycles 97 | * write ce2write hold (tdht) = 10ns = 2 cycles - 1 = 1 98 | * read latency = 450 ns = 72 cycles, crop at 63 cycles 99 | * read ce2read su (trdl - trcs) = 45-45 = 0 ns = 0 cycles 100 | * read th = 90ns = 15 cycles (not quite clear, but best guess) 101 | */ 102 | writel( (10 << LCD_PAR_CFG_WR_WAIT_CYC_BIT) | 103 | (3 << LCD_PAR_CFG_WR_TSU_BIT) | 104 | (1 << LCD_PAR_CFG_WR_TH_BIT) | 105 | /* this might need to be shorter?? */ 106 | (63 << LCD_PAR_CFG_RD_LATENCY_CYC_BIT) | 107 | (0 << LCD_PAR_CFG_RD_TSU_BIT) | 108 | (15 << LCD_PAR_CFG_RD_TH_BIT), 109 | LCD_PAR0_CFG_REG); 110 | 111 | /* 9 bit width, tchw is 0 for this chipset 112 | * (back2back writes allowed) 113 | */ 114 | writel( (0 << LCD_PAR_W2W_WAIT0_BIT) | 115 | (LCD_PAR_BUS_WIDTH_9BIT << LCD_PAR_BUS_WIDTH0_BIT), 116 | LCD_PAR_DATA_WIDTH_REG); 117 | 118 | /* Set up tear control */ 119 | //writel(LCD_TEARING_MODE_HSYNC | LCD_TEARING_ENABLE, LCD_TEARING_REG); 120 | //writel(0x0003000f, LCD_TEARING_LCD_SIZE_REG); 121 | //writel(4, LCD_TEARING_SYNC_CNT_REG); 122 | 123 | //writel(0x10000 | LCD_GMC_CTRL_ENABLE | 4, LCD_GMC_CTRL_REG); 124 | //writel(15, LCD_FREERUN_RATE_REG); 125 | //writel(20 << LCD_FREERUN_DBI_THRESH_HIGH_SHIFT, LCD_FREERUN_DBI_THRESH_REG); 126 | //writel(20 << LCD_FREERUN_GMC_THRESH_HIGH_SHIFT, LCD_FREERUN_GMC_THRESH_REG); 127 | 128 | /* Point freerunning DMA engine at parallel LCD registers */ 129 | writew((uint16_t)LCD_PAR0_CMD_PORT_REG, LCD_AUTOCOPY_CMD_ADDR_REG); 130 | writew((uint16_t)LCD_PAR0_DAT_PORT_REG, LCD_AUTOCOPY_DATA_ADDR_REG); 131 | 132 | return 0; 133 | } 134 | 135 | static void lcd_panel_setup(void) 136 | { 137 | writew(LCD_RESET_CLEAR, LCD_RESET_REG); 138 | _usleep(20000); 139 | writew(LCD_RESET_SET, LCD_RESET_REG); 140 | _msleep(20); 141 | writew(LCD_RESET_CLEAR, LCD_RESET_REG); 142 | _msleep(150); 143 | 144 | lcd_cmd(0x11); //Exit Sleep 145 | _msleep(50); // Delay 50ms 146 | lcd_cmd(0xC0); //Power control 147 | lcd_dat(0x26); 148 | lcd_cmd(0xC1); //Power control 149 | lcd_dat(0x11); //SAP[2:0];BT[3:0] 150 | lcd_cmd(0xC5); //VCM control 151 | lcd_dat(0x35); 152 | lcd_dat(0x3E); 153 | lcd_cmd(0xc7); 154 | lcd_dat(0xbe); 155 | 156 | lcd_cmd(0x36); // Memory Access Control 157 | lcd_dat(0x48); 158 | 159 | lcd_cmd(0x3a); // pixel format set 160 | lcd_dat(0x55); // 16bpp 161 | 162 | lcd_cmd(0xB1); // Frame Rate Control 163 | lcd_dat(0x00); 164 | lcd_dat(0x1b); 165 | 166 | //--------------ddram --------------------- 167 | lcd_cmd(0x2a); // column set 168 | lcd_dat(0x00); 169 | lcd_dat(0x00); 170 | lcd_dat(0x00); 171 | lcd_dat(0xEF); 172 | lcd_cmd(0x2b); // page address set 173 | lcd_dat(0x00); 174 | lcd_dat(0x00); 175 | lcd_dat(0x01); 176 | lcd_dat(0x3F); 177 | lcd_cmd(0x34); // tearing effect off 178 | //lcd_cmd(0x35); // tearing effect on 179 | //lcd_cmd(0xb4); // display inversion 180 | //lcd_dat(0x00,0x00); 181 | lcd_cmd(0xb7); //entry mode set 182 | lcd_dat(0x07); 183 | //-----------------display--------------------- 184 | lcd_cmd(0xb6); // display function control 185 | lcd_dat(0x0a); 186 | lcd_dat(0x82); 187 | lcd_dat(0x27); 188 | lcd_dat(0x00); 189 | lcd_cmd(0x11); //sleep out 190 | _msleep(100); 191 | lcd_cmd(0x29); // display on 192 | _msleep(100); 193 | 194 | /* Memory Write -- prep for the first pixel to be written */ 195 | lcd_cmd(0x2c); 196 | } 197 | 198 | /* Fill pre-frame command buffer. These commands are sent out before 199 | * pixel data, whenever RUN is enabled. 200 | */ 201 | static void lcd_fill_cmd_buffer(void) 202 | { 203 | int ncommands = 0; 204 | 205 | /* Memory write */ 206 | lcd_slot(SLOT_CMD, 0x2c, ncommands++); 207 | 208 | /* Count the number of commands and add it to AUTOCOPY_CTRL */ 209 | writel((readl(LCD_AUTOCOPY_CTRL_REG) 210 | & ~LCD_AUTOCOPY_CTRL_CMD_COUNT_MASK) 211 | | ((ncommands - 1) << LCD_AUTOCOPY_CTRL_CMD_COUNT_SHIFT), 212 | LCD_AUTOCOPY_CTRL_REG); 213 | } 214 | 215 | static int lcd_dma_setup(void) 216 | { 217 | /* Set up AUTOCOPY (i.e. freerunning mode) */ 218 | writel(LCD_FORMAT | (0x1f << LCD_AUTOCOPY_CTRL_PERIOD_SHIFT), 219 | LCD_AUTOCOPY_CTRL_REG); 220 | writel((fb_height << 16) | (fb_width), LCD_AUTOCOPY_SIZE_REG); 221 | writel(0, LCD_AUTOCOPY_OFFSET_REG); 222 | 223 | writel((uint32_t)fb, LCD_LAYER0_SRC_ADDR_REG); 224 | writel(LCD_LAYER_CTRL_CLRDPT_RGB565, LCD_LAYER0_CTRL_REG); 225 | writel((fb_height << 16) | (fb_width), LCD_LAYER0_SIZE_REG); 226 | writel(fb_width * fb_bpp, LCD_LAYER0_PITCH_REG); 227 | writel(0, LCD_LAYER0_MEM_OFFSET_REG); 228 | writel(0, LCD_LAYER0_OFFSET_REG); 229 | writel(0, LCD_LAYER0_SRC_KEY_REG); 230 | 231 | writel(rgb(0, 255, 255), LCD_AUTOCOPY_BG_COLOR_REG); 232 | 233 | writel(readl(LCD_AUTOCOPY_CTRL_REG) | LCD_AUTOCOPY_CTRL_EN0, 234 | LCD_AUTOCOPY_CTRL_REG); 235 | 236 | /* Enable AUTOCOPY_CTRL command transfer */ 237 | writel(readl(LCD_AUTOCOPY_CTRL_REG) 238 | | LCD_AUTOCOPY_CTRL_ENC 239 | | LCD_AUTOCOPY_CTRL_SEND_RESIDUE, 240 | LCD_AUTOCOPY_CTRL_REG); 241 | return 0; 242 | } 243 | 244 | int lcd_init(void) 245 | { 246 | lcd_setup(); 247 | lcd_panel_setup(); 248 | lcd_dma_setup(); 249 | return 0; 250 | } 251 | 252 | int lcd_run(void) 253 | { 254 | writew(0, LCD_RUN_REG); 255 | 256 | /* Must refill the command buffer before sending another frame */ 257 | lcd_fill_cmd_buffer(); 258 | 259 | writew(LCD_RUN_BIT, LCD_RUN_REG); 260 | return 0; 261 | } 262 | 263 | int lcd_stop(void) 264 | { 265 | writew(1, LCD_RUN_REG); 266 | writew(0, LCD_RUN_REG); 267 | return 0; 268 | } 269 | 270 | pixel_t *lcd_fb(void) 271 | { 272 | return fb; 273 | } 274 | 275 | uint32_t lcd_width(void) 276 | { 277 | return fb_width; 278 | } 279 | 280 | uint32_t lcd_height(void) 281 | { 282 | return fb_height; 283 | } 284 | 285 | uint32_t lcd_bpp(void) 286 | { 287 | return fb_bpp; 288 | } 289 | 290 | void lcd_addpixel(pixel_t px) 291 | { 292 | lcd_dat(px >> 8); 293 | lcd_dat(px & 0xff); 294 | } 295 | -------------------------------------------------------------------------------- /lib/libgcc-armv5.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isogashii/fernly/2e744ec6e25e57dbdc0a1f2e029adc0d22c922f5/lib/libgcc-armv5.a -------------------------------------------------------------------------------- /magic.mk: -------------------------------------------------------------------------------- 1 | # This file expects that OBJ contains a list of all of the object files. 2 | # The directory portion of each object file is used to locate the source 3 | # and should not contain any ..'s but rather be relative to the top of the 4 | # tree. 5 | # 6 | # So for example, py/map.c would have an object file name py/map.o 7 | # The object files will go into the build directory and mantain the same 8 | # directory structure as the source tree. So the final dependency will look 9 | # like this: 10 | # 11 | # build/py/map.o: py/map.c 12 | # 13 | # We set vpath to point to the top of the tree so that the source files 14 | # can be located. By following this scheme, it allows a single build rule 15 | # to be used to compile all .c files. 16 | 17 | vpath %.S . $(TOP) 18 | $(BUILD)/%.o: %.S 19 | $(ECHO) "AS $<" 20 | $(Q)$(AS) $(AFLAGS) -c -o $@ $< 21 | 22 | vpath %.s . $(TOP) 23 | $(BUILD)/%.o: %.s 24 | $(ECHO) "AS $<" 25 | $(Q)$(AS) -o $@ $< 26 | 27 | define compile_c 28 | $(ECHO) "CC $<" 29 | $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< 30 | @# The following fixes the dependency file. 31 | @# See http://make.paulandlesley.org/autodep.html for details. 32 | @$(CP) $(@:.o=.d) $(@:.o=.P); \ 33 | $(SED) -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ 34 | -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ 35 | $(RM) -f $(@:.o=.d) 36 | endef 37 | 38 | vpath %.c . $(TOP) 39 | $(BUILD)/%.o: %.c 40 | $(call compile_c) 41 | 42 | $(BUILD)/%.pp: %.c 43 | $(ECHO) "PreProcess $<" 44 | $(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $< 45 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bionic.h" 3 | #include "memio.h" 4 | #include "printf.h" 5 | #include "serial.h" 6 | #include "utils.h" 7 | #include "scriptic.h" 8 | 9 | #include "fernvale-pmic.h" 10 | 11 | //#define AUTOMATED 12 | 13 | #if !defined(AUTOMATED) 14 | #define PROMPT "fernly> " 15 | 16 | static int serial_get_line(char *bfr, int len) 17 | { 18 | int cur = 0; 19 | 20 | while (cur < len) { 21 | bfr[cur] = serial_getc(); 22 | serial_putc(bfr[cur]); 23 | 24 | /* Carriage Return */ 25 | if (bfr[cur] == '\n') { 26 | bfr[cur] = '\0'; 27 | return 0; 28 | } 29 | 30 | /* Linefeed */ 31 | else if (bfr[cur] == '\r') { 32 | bfr[cur] = '\0'; 33 | return 0; 34 | } 35 | 36 | /* Backspace */ 37 | else if (bfr[cur] == 0x7f) { 38 | bfr[cur] = '\0'; 39 | 40 | if (cur > 0) { 41 | serial_putc('\b'); 42 | serial_putc(' '); 43 | serial_putc('\b'); 44 | cur--; 45 | } 46 | } 47 | 48 | /* Ctrl-U */ 49 | else if (bfr[cur] == 0x15) { 50 | while (cur > 0) { 51 | serial_putc('\b'); 52 | serial_putc(' '); 53 | serial_putc('\b'); 54 | bfr[cur] = '\0'; 55 | cur--; 56 | } 57 | } 58 | 59 | /* Ctrl-W */ 60 | else if (bfr[cur] == 0x17) { 61 | while (cur > 0 && bfr[cur] != ' ') { 62 | serial_putc('\b'); 63 | serial_putc(' '); 64 | serial_putc('\b'); 65 | bfr[cur] = '\0'; 66 | cur--; 67 | } 68 | } 69 | 70 | /* Escape code */ 71 | else if (bfr[cur] == 0x1b) { 72 | /* Next two characters are escape codes */ 73 | uint8_t next = serial_getc(); 74 | /* Sanity check: next should be '[' */ 75 | (void)next; 76 | 77 | next = serial_getc(); 78 | } 79 | else 80 | cur++; 81 | } 82 | bfr[len - 1] = '\0'; 83 | return -1; 84 | } 85 | #endif 86 | 87 | static int list_registers(void) 88 | { 89 | int var; 90 | 91 | serial_puts("Registers:\n"); 92 | 93 | serial_puts("CPSR: "); 94 | asm volatile ("mrs %0, cpsr":"=r" (var)); 95 | serial_puth(var, 8); 96 | serial_puts("\n"); 97 | 98 | serial_puts("SPSR: "); 99 | asm volatile ("mrs %0, spsr":"=r" (var)); 100 | serial_puth(var, 8); 101 | serial_puts("\n"); 102 | 103 | serial_puts("R0: "); 104 | asm volatile ("mov %0, r0":"=r" (var)); 105 | serial_puth(var, 8); 106 | serial_puts("\n"); 107 | 108 | serial_puts("R1: "); 109 | asm volatile ("mov %0, r1":"=r" (var)); 110 | serial_puth(var, 8); 111 | serial_puts("\n"); 112 | 113 | serial_puts("R2: "); 114 | asm volatile ("mov %0, r2":"=r" (var)); 115 | serial_puth(var, 8); 116 | serial_puts("\n"); 117 | 118 | serial_puts("R3: "); 119 | asm volatile ("mov %0, r3":"=r" (var)); 120 | serial_puth(var, 8); 121 | serial_puts("\n"); 122 | 123 | serial_puts("R4: "); 124 | asm volatile ("mov %0, r4":"=r" (var)); 125 | serial_puth(var, 8); 126 | serial_puts("\n"); 127 | 128 | serial_puts("R5: "); 129 | asm volatile ("mov %0, r5":"=r" (var)); 130 | serial_puth(var, 8); 131 | serial_puts("\n"); 132 | 133 | serial_puts("R6: "); 134 | asm volatile ("mov %0, r6":"=r" (var)); 135 | serial_puth(var, 8); 136 | serial_puts("\n"); 137 | 138 | serial_puts("R7: "); 139 | asm volatile ("mov %0, r7":"=r" (var)); 140 | serial_puth(var, 8); 141 | serial_puts("\n"); 142 | 143 | serial_puts("R8: "); 144 | asm volatile ("mov %0, r8":"=r" (var)); 145 | serial_puth(var, 8); 146 | serial_puts("\n"); 147 | 148 | serial_puts("R9: "); 149 | asm volatile ("mov %0, r9":"=r" (var)); 150 | serial_puth(var, 8); 151 | serial_puts("\n"); 152 | 153 | serial_puts("R10: "); 154 | asm volatile ("mov %0, r10":"=r" (var)); 155 | serial_puth(var, 8); 156 | serial_puts("\n"); 157 | 158 | serial_puts("FP: "); 159 | asm volatile ("mov %0, r11":"=r" (var)); 160 | serial_puth(var, 8); 161 | serial_puts("\n"); 162 | 163 | serial_puts("IP: "); 164 | asm volatile ("mov %0, r12":"=r" (var)); 165 | serial_puth(var, 8); 166 | serial_puts("\n"); 167 | 168 | serial_puts("SP: "); 169 | asm volatile ("mov %0, r13":"=r" (var)); 170 | serial_puth(var, 8); 171 | serial_puts("\n"); 172 | 173 | serial_puts("LR: "); 174 | asm volatile ("mov %0, r14":"=r" (var)); 175 | serial_puth(var, 8); 176 | serial_puts("\n"); 177 | 178 | serial_puts("PC: "); 179 | asm volatile ("mov %0, r15":"=r" (var)); 180 | serial_puth(var, 8); 181 | serial_puts("\n"); 182 | 183 | return 0; 184 | } 185 | 186 | static int shell_run_command(char *line); 187 | static int do_init(void) 188 | { 189 | serial_init(); 190 | 191 | list_registers(); 192 | 193 | /* Disable system watchdog */ 194 | writel(0x2200, 0xa0030000); 195 | 196 | /* Enable USB Download mode (required for no-battery operation) */ 197 | writew(0x8000, PMIC_CTRL10); 198 | 199 | /* Disable battery watchdog */ 200 | writew(0x2, PMIC_CTRL9); 201 | 202 | scriptic_run("set_plls"); 203 | scriptic_run("enable_psram"); 204 | serial_puts("\n\nFernly shell\n"); 205 | shell_run_command("bl 5"); 206 | shell_run_command("lcd init"); 207 | shell_run_command("lcd tpd"); 208 | 209 | /* Initialize the keypad */ 210 | scriptic_run("set_kbd"); 211 | 212 | return 0; 213 | } 214 | 215 | #ifdef AUTOMATED 216 | static inline int get_hex(int bytes) 217 | { 218 | uint32_t word = 0; 219 | uint8_t buf; 220 | int i; 221 | 222 | if (bytes == 4) 223 | i = 28; 224 | else if (bytes == 2) 225 | i = 12; 226 | else 227 | i = 4; 228 | 229 | while (i >= 0) { 230 | buf = serial_getc(); 231 | if (buf > 96) 232 | buf -= 87; 233 | else if (buf > 64) 234 | buf -= 55; 235 | else 236 | buf -= 48; 237 | word |= (buf << i); 238 | 239 | i -= 4; 240 | } 241 | return word; 242 | } 243 | 244 | /* Protocol: 245 | * Stream is byte-oriented. The following commands are known: 246 | * 247 | * r - read an address 248 | * w - write to an address 249 | * z - zero-fill a region 250 | * 251 | * Responses: 252 | * 253 | * k - Ready for command 254 | * ? - Unknown command 255 | */ 256 | static int loop(void) 257 | { 258 | int buf; 259 | int size; 260 | uint32_t offset; 261 | uint32_t value; 262 | 263 | serial_putc('k'); 264 | buf = serial_getc(); 265 | 266 | switch (buf) { 267 | /* Read. Format: r[otf]aaaaaaaa 268 | otf -> read One, Two, or Four bytes 269 | a.. -> address to read 270 | */ 271 | case 'r': 272 | size = serial_getc(); 273 | if (size == 'o') { 274 | offset = get_hex(4); 275 | value = readb(offset); 276 | serial_puth(value, 2); 277 | } 278 | else if (size == 't') { 279 | offset = get_hex(4); 280 | value = readw(offset); 281 | serial_puth(value, 4); 282 | } 283 | else { 284 | offset = get_hex(4); 285 | value = readl(offset); 286 | serial_puth(value, 8); 287 | } 288 | break; 289 | 290 | case 'f': 291 | size = get_hex(4); 292 | break; 293 | 294 | /* Write. Format: w[otf]aaaaaaaavvvvvvvv 295 | otf -> write One, Two, or Four bytes 296 | a.. -> address to write 297 | v.. -> value to write 298 | */ 299 | case 'w': 300 | size = serial_getc(); 301 | if (size == 'o') { 302 | offset = get_hex(4); 303 | value = get_hex(1); 304 | writeb(value, offset); 305 | serial_puth(value, 2); 306 | } 307 | else if (size == 't') { 308 | offset = get_hex(4); 309 | value = get_hex(2); 310 | writew(value, offset); 311 | serial_puth(value, 4); 312 | } 313 | else { 314 | offset = get_hex(4); 315 | value = get_hex(4); 316 | writel(value, offset); 317 | serial_puth(value, 8); 318 | } 319 | break; 320 | 321 | case 'z': { 322 | uint32_t start; 323 | uint32_t end; 324 | 325 | start = get_hex(4); 326 | end = get_hex(4); 327 | while (start < end) { 328 | *((uint32_t *)start) = 0; 329 | start += 4; 330 | } 331 | } 332 | break; 333 | 334 | default: 335 | serial_putc('?'); 336 | break; 337 | } 338 | return 0; 339 | } 340 | #else /* AUTOMATED */ 341 | 342 | static int cmd_help(int argc, char **argv); 343 | extern int cmd_hex(int argc, char **argv); 344 | extern int cmd_irq(int argc, char **argv); 345 | extern int cmd_msleep(int argc, char **argv); 346 | extern int cmd_peek(int argc, char **argv); 347 | extern int cmd_poke(int argc, char **argv); 348 | extern int cmd_spi(int argc, char **argv); 349 | extern int cmd_spi_raw(int argc, char **argv); 350 | extern int cmd_swi(int argc, char **argv); 351 | extern int cmd_reboot(int argc, char **argv); 352 | extern int cmd_led(int argc, char **argv); 353 | extern int cmd_bl(int argc, char **argv); 354 | extern int cmd_lcd(int argc, char **argv); 355 | extern int cmd_load(int argc, char **argv); 356 | extern int cmd_loadjump(int argc, char **argv); 357 | extern int cmd_keypad(int argc, char **argv); 358 | 359 | static const struct { 360 | int (*func)(int argc, char **argv); 361 | const char *name; 362 | const char *help; 363 | } commands[] = { 364 | { 365 | .func = cmd_help, 366 | .name = "help", 367 | .help = "Print help about available commands", 368 | }, 369 | { 370 | .func = cmd_reboot, 371 | .name = "reboot", 372 | .help = "Reboot Fernvale", 373 | }, 374 | { 375 | .func = cmd_msleep, 376 | .name = "msleep", 377 | .help = "Sleep for some number of milliseconds", 378 | }, 379 | { 380 | .func = cmd_hex, 381 | .name = "hex", 382 | .help = "Print area of memory as hex", 383 | }, 384 | { 385 | .func = cmd_peek, 386 | .name = "peek", 387 | .help = "Look at one area of memory", 388 | }, 389 | { 390 | .func = cmd_poke, 391 | .name = "poke", 392 | .help = "Write a value to an area of memory", 393 | }, 394 | { 395 | .func = cmd_irq, 396 | .name = "irq", 397 | .help = "Manipulate IRQs", 398 | }, 399 | { 400 | .func = cmd_spi, 401 | .name = "spi", 402 | .help = "Manipulate on-board SPI", 403 | }, 404 | { 405 | .func = cmd_spi_raw, 406 | .name = "spi_raw", 407 | .help = "Manipulate on-board SPI (raw interface)", 408 | }, 409 | { 410 | .func = cmd_swi, 411 | .name = "swi", 412 | .help = "Generate software interrupt", 413 | }, 414 | { 415 | .func = cmd_led, 416 | .name = "led", 417 | .help = "Turn the on-board LED on or off", 418 | }, 419 | { 420 | .func = cmd_bl, 421 | .name = "bl", 422 | .help = "Set the LCD backlight brightness", 423 | }, 424 | { 425 | .func = cmd_lcd, 426 | .name = "lcd", 427 | .help = "Manipulate the LCD", 428 | }, 429 | { 430 | .func = cmd_load, 431 | .name = "load", 432 | .help = "Load data to a specific area in memory", 433 | }, 434 | { 435 | .func = cmd_loadjump, 436 | .name = "loadjmp", 437 | .help = "Load data to a specific area in memory, " 438 | "then jump to it", 439 | }, 440 | { 441 | .func = cmd_keypad, 442 | .name = "keypad", 443 | .help = "Read keys from keypad until # is pressed ", 444 | }, 445 | }; 446 | 447 | int cmd_help(int argc, char **argv) 448 | { 449 | int i; 450 | 451 | printf("Fernly shell help. Available commands:\n"); 452 | for (i = 0; i < sizeof(commands) / sizeof(*commands); i++) { 453 | serial_puts("\t"); 454 | serial_puts(commands[i].name); 455 | serial_puts("\t"); 456 | serial_puts(commands[i].help); 457 | serial_puts("\n"); 458 | } 459 | return 0; 460 | } 461 | 462 | static int shell_run_command(char *line) 463 | { 464 | char *lp, *cmd, *tokp; 465 | char *args[8]; 466 | int i, n; 467 | 468 | lp = _strtok(line, " \t", &tokp); 469 | cmd = lp; 470 | n = 0; 471 | while ((lp = _strtok(NULL, " \t", &tokp)) != NULL) { 472 | if (n >= 7) { 473 | printf("too many arguments\r\n"); 474 | cmd = NULL; 475 | break; 476 | } 477 | args[n++] = lp; 478 | } 479 | args[n] = NULL; 480 | if (cmd == NULL) 481 | return -1; 482 | 483 | for (i = 0; i < sizeof(commands) / sizeof(*commands); i++) 484 | if (!_strcasecmp(commands[i].name, cmd)) 485 | return commands[i].func(n, args); 486 | 487 | printf("Unknown command: %s\n", cmd); 488 | 489 | return 0; 490 | } 491 | 492 | static int loop(void) 493 | { 494 | char line[256]; 495 | 496 | serial_puts(PROMPT); 497 | serial_get_line(line, sizeof(line)); 498 | printf("\n"); 499 | return shell_run_command(line); 500 | } 501 | #endif /* ! AUTOMATED */ 502 | 503 | int main(void) 504 | { 505 | do_init(); 506 | 507 | while (1) 508 | loop(); 509 | 510 | return 0; 511 | } 512 | -------------------------------------------------------------------------------- /memio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | inline void writeb(uint8_t value, uint32_t addr) 4 | { 5 | *((volatile uint8_t *)addr) = value; 6 | } 7 | 8 | inline uint8_t readb(uint32_t addr) 9 | { 10 | return *(volatile uint8_t *)addr; 11 | } 12 | 13 | inline void writew(uint16_t value, uint32_t addr) 14 | { 15 | *((volatile uint16_t *)addr) = value; 16 | } 17 | 18 | inline uint16_t readw(uint32_t addr) 19 | { 20 | return *(volatile uint16_t *)addr; 21 | } 22 | 23 | inline void writel(uint32_t value, uint32_t addr) 24 | { 25 | *((volatile uint32_t *)addr) = value; 26 | } 27 | 28 | inline uint32_t readl(uint32_t addr) 29 | { 30 | return *(volatile uint32_t *)addr; 31 | } 32 | -------------------------------------------------------------------------------- /mkenv.mk: -------------------------------------------------------------------------------- 1 | ifneq ($(lastword a b),b) 2 | $(error These Makefiles require make 3.81 or newer) 3 | endif 4 | 5 | # Set TOP to be the path to get from the current directory (where make was 6 | # invoked) to the top of the tree. $(lastword $(MAKEFILE_LIST)) returns 7 | # the name of this makefile relative to where make was invoked. 8 | # 9 | # We assume that this file is in the py directory so we use $(dir ) twice 10 | # to get to the top of the tree. 11 | 12 | THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) 13 | TOP := $(patsubst %/py/mkenv.mk,%,$(THIS_MAKEFILE)) 14 | 15 | # Turn on increased build verbosity by defining BUILD_VERBOSE in your main 16 | # Makefile or in your environment. You can also use V=1 on the make command 17 | # line. 18 | 19 | ifeq ("$(origin V)", "command line") 20 | BUILD_VERBOSE=$(V) 21 | endif 22 | ifndef BUILD_VERBOSE 23 | BUILD_VERBOSE = 0 24 | endif 25 | ifeq ($(BUILD_VERBOSE),0) 26 | Q = @ 27 | else 28 | Q = 29 | endif 30 | # Since this is a new feature, advertise it 31 | ifeq ($(BUILD_VERBOSE),0) 32 | $(info Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.) 33 | endif 34 | 35 | # default settings; can be overriden in main Makefile 36 | 37 | BUILD ?= build 38 | 39 | RM = rm 40 | ECHO = @echo 41 | CP = cp 42 | MKDIR = mkdir 43 | SED = sed 44 | PYTHON = python 45 | 46 | AS = $(CROSS_COMPILE)gcc $(CFLAGS) -D__ASSEMBLY__ 47 | CC = $(CROSS_COMPILE)gcc 48 | LD = $(CROSS_COMPILE)ld 49 | OBJCOPY = $(CROSS_COMPILE)objcopy 50 | SIZE = $(CROSS_COMPILE)size 51 | STRIP = $(CROSS_COMPILE)strip 52 | 53 | CC_NATIVE ?= gcc 54 | 55 | all: 56 | .PHONY: all 57 | 58 | .DELETE_ON_ERROR: 59 | 60 | MKENV_INCLUDED = 1 61 | -------------------------------------------------------------------------------- /pcap-parse/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc parse-commands.c -o parse-commands -lpcap -Wall 3 | -------------------------------------------------------------------------------- /pcap-parse/mt6261.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isogashii/fernly/2e744ec6e25e57dbdc0a1f2e029adc0d22c922f5/pcap-parse/mt6261.pcap -------------------------------------------------------------------------------- /pcap-parse/parse-commands.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | struct usb_pkt { 16 | uint8_t ignored1[16]; 17 | uint8_t incoming; 18 | uint8_t ignored2[6]; 19 | uint32_t length; 20 | uint8_t data[0]; 21 | } __attribute__((__packed__)); 22 | 23 | static int get_next_pkt(pcap_t *pcap, struct usb_pkt **pkt) { 24 | int ret; 25 | struct pcap_pkthdr *header; 26 | 27 | do { 28 | ret = pcap_next_ex(pcap, &header, (const uint8_t **)pkt); 29 | if (ret != 1) 30 | break; 31 | } while (((*pkt)->incoming)); 32 | 33 | return (ret == 1); 34 | } 35 | 36 | int main(int argc, char **argv) { 37 | char *filename; 38 | char pcap_err[PCAP_ERRBUF_SIZE]; 39 | pcap_t *pcap; 40 | struct usb_pkt *pkt; 41 | uint32_t pkt_index = 0; 42 | 43 | if (argc != 2) { 44 | printf("Usage: %s [dumpfile.pcap]\n", argv[0]); 45 | return 1; 46 | } 47 | 48 | filename = argv[1]; 49 | pcap = pcap_open_offline(filename, pcap_err); 50 | 51 | if (!pcap) { 52 | fprintf(stderr, "Unable to open pcap file: %s\n", pcap_err); 53 | return 1; 54 | } 55 | 56 | /* Seek to offset 598, which is where command 0xd7 starts */ 57 | while (get_next_pkt(pcap, &pkt)) { 58 | pkt_index++; 59 | 60 | if ((pkt->length == 1) && (pkt->data[0] == 0xd7)) { 61 | uint32_t addr; 62 | uint32_t bytes; 63 | uint32_t sig_bytes; 64 | printf("Found download at offset %d\n", pkt_index); 65 | 66 | get_next_pkt(pcap, &pkt); 67 | memcpy(&addr, pkt->data, 4); 68 | printf("Writing to address 0x%08x\n", be32toh(addr)); 69 | 70 | get_next_pkt(pcap, &pkt); 71 | memcpy(&bytes, pkt->data, 4); 72 | printf("Writing %d bytes\n", be32toh(bytes)); 73 | 74 | get_next_pkt(pcap, &pkt); 75 | memcpy(&sig_bytes, pkt->data, 4); 76 | printf("Signature is %d bytes\n", be32toh(sig_bytes)); 77 | 78 | printf("\n"); 79 | 80 | uint8_t data[be32toh(bytes)]; 81 | uint32_t copied = 0; 82 | while (copied < be32toh(bytes)) { 83 | int ret; 84 | ret = get_next_pkt(pcap, &pkt); 85 | if (!ret) { 86 | fprintf(stderr, "Packet cut short\n"); 87 | break; 88 | } 89 | memcpy(data + copied, pkt->data, pkt->length); 90 | copied += pkt->length; 91 | } 92 | 93 | char name[32]; 94 | snprintf(name, sizeof(name) - 1, "prog-0x%08x", be32toh(addr)); 95 | int fd = open(name, O_WRONLY | O_CREAT, 0777); 96 | if (fd == -1) { 97 | perror("Unable to open file for writing"); 98 | return 1; 99 | } 100 | write(fd, data, sizeof(data)); 101 | close(fd); 102 | } 103 | } 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /scriptic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "scriptic.h" 3 | #include "bionic.h" 4 | #include "memio.h" 5 | 6 | //#define SCRIPTIC_DEBUG /* Enable this to print commands as they're executed */ 7 | 8 | extern struct scriptic set_plls; 9 | extern struct scriptic enable_psram; 10 | extern struct scriptic spi_run; 11 | extern struct scriptic spi_run; 12 | extern struct scriptic spi_init; 13 | extern struct scriptic set_kbd; 14 | 15 | static struct scriptic *scripts[] = { 16 | &set_plls, 17 | &enable_psram, 18 | &spi_run, 19 | &spi_init, 20 | &set_kbd, 21 | }; 22 | 23 | #ifdef SCRIPTIC_DEBUG 24 | static void sc_print_header(void *p) 25 | { 26 | union scriptic_command *cmd = p; 27 | 28 | switch(cmd->header.command) { 29 | case sc_end_cmd: 30 | printf("end script"); 31 | break; 32 | 33 | case sc_read32_cmd: 34 | if (cmd->read32.mask == 0 || cmd->read32.mask == 0xffffffff) 35 | printf(" read32 @ 0x%08x", cmd->read32.addr); 36 | else 37 | printf(" read32 @ 0x%08x, mask 0x%08x, match 0x%08x", 38 | cmd->read32.addr, 39 | cmd->read32.mask, 40 | cmd->read32.match); 41 | break; 42 | 43 | case sc_read16_cmd: 44 | if (cmd->read16.mask == 0 || cmd->read16.mask == 0xffff) 45 | printf(" read16 @ 0x%08x", cmd->read16.addr); 46 | else 47 | printf(" read16 @ 0x%08x, mask 0x%04x, match 0x%04x", 48 | cmd->read16.addr, 49 | cmd->read16.mask, 50 | cmd->read16.match); 51 | break; 52 | 53 | case sc_write32_cmd: 54 | if (cmd->write32.mask == 0 || cmd->write32.mask == 0xffffffff) 55 | printf(" write32 0x%08x @ 0x%08x", 56 | cmd->write32.value, cmd->write32.addr); 57 | else 58 | printf(" write32 0x%08x (mask 0x%08x) @ 0x%08x", 59 | cmd->write32.value, 60 | cmd->write32.mask, 61 | cmd->write32.addr); 62 | break; 63 | 64 | case sc_write16_cmd: 65 | if (cmd->write16.mask == 0 || cmd->write16.mask == 0xffff) 66 | printf(" write16 0x%04x @ 0x%08x", 67 | cmd->write16.value, cmd->write16.addr); 68 | else 69 | printf(" write16 0x%04x (mask 0x%04x) @ 0x%08x", 70 | cmd->write16.value, 71 | cmd->write16.mask, 72 | cmd->write16.addr); 73 | break; 74 | 75 | case sc_call_cmd: 76 | printf(" call function @ 0x%08x with arg 0x%08x", 77 | (uint32_t)cmd->call.func, 78 | (uint32_t)cmd->call.opaque); 79 | break; 80 | 81 | case sc_usleep_cmd: 82 | printf(" usleep for %d usecs", cmd->usleep.usecs); 83 | break; 84 | 85 | default: 86 | printf(" unrecognized command"); 87 | } 88 | 89 | printf("\n"); 90 | } 91 | #endif /* SCRIPTIC_DEBUG */ 92 | 93 | static int sc_header_command(struct scriptic_header *header) 94 | { 95 | return header->command; 96 | } 97 | 98 | static int sc_command_size(void *header) { 99 | switch(sc_header_command(header)) { 100 | case sc_end_cmd: return sizeof(struct scriptic_end); 101 | case sc_read32_cmd: return sizeof(struct scriptic_read32); 102 | case sc_write32_cmd: return sizeof(struct scriptic_write32); 103 | case sc_read16_cmd: return sizeof(struct scriptic_read16); 104 | case sc_write16_cmd: return sizeof(struct scriptic_write16); 105 | case sc_call_cmd: return sizeof(struct scriptic_call); 106 | case sc_usleep_cmd: return sizeof(struct scriptic_usleep); 107 | default: return sizeof(struct scriptic_header); 108 | } 109 | } 110 | 111 | static struct scriptic_header *sc_next_command(void *header) 112 | { 113 | return header + sc_command_size(header); 114 | } 115 | 116 | static int sc_command_count(struct scriptic *script) 117 | { 118 | uint32_t count = 1; 119 | struct scriptic_header *header = (struct scriptic_header *)&script[1]; 120 | 121 | for (count = 0; sc_header_command(header) != sc_end_cmd; count++) { 122 | header->index = count; 123 | header = sc_next_command(header); 124 | } 125 | header->index = count; 126 | 127 | return count; 128 | } 129 | 130 | /* Command functions */ 131 | 132 | static void sc_read32(struct scriptic_read32 *pkt) 133 | { 134 | if ((pkt->mask == 0) || (pkt->mask == 0xffffffff)) 135 | (void)readl(pkt->addr); 136 | else { 137 | while (1) { 138 | uint32_t val = readl(pkt->addr); 139 | if ((val & pkt->mask) == (pkt->match & pkt->mask) ) 140 | break; 141 | } 142 | } 143 | } 144 | 145 | static void sc_read16(struct scriptic_read16 *pkt) 146 | { 147 | if ((pkt->mask == 0) || (pkt->mask == 0xffff)) 148 | (void)readw(pkt->addr); 149 | else 150 | while (1) { 151 | uint16_t val = readw(pkt->addr); 152 | if ((val & pkt->mask) == (pkt->match & pkt->mask) ) 153 | break; 154 | } 155 | } 156 | 157 | static void sc_write32(struct scriptic_write32 *pkt) 158 | { 159 | if ((pkt->mask == 0) || (pkt->mask == 0xffffffff)) { 160 | writel(pkt->value, pkt->addr); 161 | } 162 | else { 163 | uint32_t tmp; 164 | tmp = readl(pkt->addr); 165 | tmp &= ~pkt->mask; 166 | tmp |= (pkt->value & pkt->mask); 167 | writel(tmp, pkt->addr); 168 | } 169 | } 170 | 171 | static void sc_write16(struct scriptic_write16 *pkt) 172 | { 173 | if ((pkt->mask == 0) || (pkt->mask == 0xffff)) { 174 | writew(pkt->value, pkt->addr); 175 | } 176 | else { 177 | uint16_t tmp; 178 | tmp = readw(pkt->addr); 179 | tmp &= ~pkt->mask; 180 | tmp |= (pkt->value & pkt->mask); 181 | writew(tmp, pkt->addr); 182 | } 183 | } 184 | 185 | static void sc_call(struct scriptic_call *pkt) 186 | { 187 | while (!pkt->func(pkt->opaque)); 188 | } 189 | 190 | void sc_usleep(struct scriptic_usleep *pkt) 191 | { 192 | uint32_t usecs; 193 | int i, j; 194 | 195 | usecs = pkt->usecs; 196 | 197 | /* Outer loop is 11 cycles total, 6 cycles on its own */ 198 | for (i = 0; i < usecs; i++) 199 | /* Inner loop is 5 cycles */ 200 | for (j = 0; j < 73; j++) 201 | asm("nop"); 202 | } 203 | 204 | /* Exported functions */ 205 | 206 | int scriptic_execute(const struct scriptic *script) 207 | { 208 | void *header; 209 | 210 | if (!script) { 211 | #ifdef SCRIPTIC_DEBUG 212 | printf("scriptic: Tried to execute a NULL script\n"); 213 | #endif 214 | return -1; 215 | } 216 | 217 | header = (struct scriptic_header *)&script[1]; 218 | 219 | #ifdef SCRIPTIC_DEBUG 220 | printf("Executing script \"%s\", v %d.%d.%d\n", 221 | script->name, 222 | script->ver_major, script->ver_minor, script->ver_rev); 223 | sc_print_header(header); 224 | #endif /* SCRIPTIC_DEBUG */ 225 | while (sc_header_command(header) != sc_end_cmd) { 226 | switch(sc_header_command(header)) { 227 | case sc_end_cmd: 228 | break; 229 | 230 | case sc_read32_cmd: 231 | sc_read32(header); 232 | break; 233 | 234 | case sc_write32_cmd: 235 | sc_write32(header); 236 | break; 237 | 238 | case sc_read16_cmd: 239 | sc_read16(header); 240 | break; 241 | 242 | case sc_write16_cmd: 243 | sc_write16(header); 244 | break; 245 | 246 | case sc_call_cmd: 247 | sc_call(header); 248 | break; 249 | 250 | case sc_usleep_cmd: 251 | sc_usleep(header); 252 | break; 253 | 254 | default: 255 | break; 256 | } 257 | 258 | header = sc_next_command(header); 259 | #ifdef SCRIPTIC_DEBUG 260 | sc_print_header(header); 261 | #endif /* SCRIPTIC_DEBUG */ 262 | } 263 | 264 | return 0; 265 | } 266 | 267 | const struct scriptic *scriptic_get(const char *name) 268 | { 269 | struct scriptic *script = NULL; 270 | int i; 271 | 272 | for (i = 0; i < sizeof(scripts) / sizeof(*scripts); i++) { 273 | if (!_strcasecmp(name, scripts[i]->name)) { 274 | script = scripts[i]; 275 | break; 276 | } 277 | } 278 | 279 | if (script && script->command_count == 0) 280 | script->command_count = sc_command_count(script); 281 | 282 | return script; 283 | } 284 | 285 | int scriptic_run(const char *name) 286 | { 287 | const struct scriptic *script; 288 | 289 | script = scriptic_get(name); 290 | if (!script) { 291 | #ifdef SCRIPTIC_DEBUG 292 | printf("scriptic: Unrecognized script name: %s\n", name); 293 | #endif 294 | return -1; 295 | } 296 | return scriptic_execute(script); 297 | } 298 | -------------------------------------------------------------------------------- /scriptic/enable-psram.S: -------------------------------------------------------------------------------- 1 | #include "scriptic.h" 2 | #include "fernvale-emi.h" 3 | 4 | sc_new "enable_psram", 1, 0, 0 5 | 6 | /* Unclear what these do, but required on some chips */ 7 | sc_write32 0x39320d61, 0, EMI_CTRL_CONB 8 | sc_write32 0x400, 0x400, EMI_CTRL_CONF 9 | 10 | sc_write32 0x401, 0, EMI_CTRL_GENA 11 | 12 | /* Remap EMI to 0x10000000, and SPI to 0x00000000 */ 13 | sc_write32 2, 0, EMI_CTRL_REMAP 14 | 15 | /* Memory configuration */ 16 | sc_read16 0, 0, 0x1ffffffe 17 | sc_usleep 50 18 | sc_read16 0, 0, 0x1ffffffe 19 | sc_usleep 50 20 | 21 | sc_write16 1, 0, 0x1ffffffe 22 | sc_usleep 50 23 | sc_write16 0x2b13, 0, 0x1ffffffe 24 | sc_usleep 50 25 | 26 | sc_read16 0, 0, 0x1ffffffe 27 | sc_usleep 50 28 | sc_read16 0, 0, 0x1ffffffe 29 | sc_usleep 50 30 | 31 | sc_write16 0, 0, 0x1ffffffe 32 | sc_usleep 50 33 | sc_write16 0x10, 0, 0x1ffffffe 34 | sc_usleep 50 35 | 36 | sc_write32 0xa0000000, 0, EMI_CTRL_CONB 37 | sc_write32 0xb2024419, 0, EMI_CTRL_CONF 38 | sc_usleep 50 39 | 40 | sc_write32 0x400, 0x400, EMI_CTRL_GENA 41 | 42 | /* Now map EMI back to 0x00000000, and SPI to 0x10000000 */ 43 | sc_write32 3, 0, EMI_CTRL_REMAP 44 | sc_usleep 50 45 | 46 | sc_write32 0x20004001, 0, EMI_CTRL_RDCT 47 | sc_write32 0x5111, 0, EMI_CTRL_DSRAM 48 | 49 | sc_write32 0, 0, EMI_CTRL_IDLA 50 | sc_write32 0, 0, EMI_CTRL_IDLB 51 | sc_write32 0, 0, EMI_CTRL_IDLC 52 | sc_write32 0, 0, EMI_CTRL_IDLD 53 | sc_write32 0, 0, EMI_CTRL_IDLE 54 | sc_write32 0, 0, EMI_CTRL_ODLA 55 | sc_write32 0, 0, EMI_CTRL_ODLB 56 | sc_write32 0, 0, EMI_CTRL_ODLC 57 | sc_write32 0, 0, EMI_CTRL_ODLD 58 | sc_write32 0, 0, EMI_CTRL_ODLE 59 | 60 | sc_write32 0x00010001, 0, EMI_CTRL_IOA 61 | sc_write32 0x00010001, 0, EMI_CTRL_IOB 62 | 63 | sc_usleep 50 64 | 65 | /* Calibrate DQ in delay */ 66 | sc_call calibrate_psram, 0 67 | 68 | sc_write32 0x300f0000, 0, EMI_CTRL_DLLV 69 | sc_read32 0x80, 0x80, EMI_CTRL_DLLV 70 | sc_write32 0x700f0000, 0, EMI_CTRL_DLLV 71 | sc_read32 0x80, 0x00, EMI_CTRL_DLLV 72 | sc_write32 0x100f0000, 0, EMI_CTRL_DLLV 73 | 74 | sc_write32 0x5426, 0, EMI_CTRL_ARBA 75 | sc_write32 0x5009, 0, EMI_CTRL_ARBB 76 | sc_write32 0x5051, 0, EMI_CTRL_ARBC 77 | 78 | sc_end 79 | -------------------------------------------------------------------------------- /scriptic/keypad.S: -------------------------------------------------------------------------------- 1 | #include "scriptic.h" 2 | #include "fernvale-gpio.h" 3 | 4 | sc_new "set_kbd", 1, 0, 0 5 | 6 | /* Set pinmux to use as Keypad instead of GPIO */ 7 | sc_write32 0x11100000, 0, GPIO_CTRL_MODE0 8 | sc_usleep 100 9 | sc_read32 0x0, 0, GPIO_CTRL_MODE0 10 | sc_write32 0x11111011, 0, GPIO_CTRL_MODE1 11 | sc_usleep 100 12 | sc_read32 0x0, 0, GPIO_CTRL_MODE1 13 | 14 | /* The keyboard controller itself is setup correctly by default, 15 | * no initialisation necessary. */ 16 | 17 | sc_end 18 | -------------------------------------------------------------------------------- /scriptic/set-plls.S: -------------------------------------------------------------------------------- 1 | #include "scriptic.h" 2 | #include "fernvale-pll.h" 3 | 4 | sc_new "set_plls", 1, 0, 0 5 | 6 | sc_write16 0, 0, PLL_CTRL_CON2 7 | sc_write16 0, 0, PLL_CTRL_CON3 8 | sc_write16 0, 0, PLL_CTRL_CON0 9 | sc_usleep 3 10 | 11 | sc_write16 1, 1, PLL_CTRL_UPLL_CON0 12 | 13 | /* Run EIM at 166 MHz */ 14 | sc_write16 0x1840, 0, PLL_CTRL_EPLL_CON0 15 | sc_write16 0x100, 0x100, PLL_CTRL_EPLL_CON1 16 | 17 | sc_write16 1, 0, PLL_CTRL_MDDS_CON0 18 | sc_write16 1, 1, PLL_CTRL_MPLL_CON0 19 | sc_usleep 1 20 | 21 | sc_write16 1, 0, PLL_CTRL_EDDS_CON0 22 | sc_write16 1, 1, PLL_CTRL_EPLL_CON0 23 | sc_usleep 70 24 | 25 | sc_write16 0x4000, 0x4000, PLL_CTRL_CLK_CONDB 26 | sc_usleep 1 27 | 28 | /* Enable digital frequency divider */ 29 | sc_write32 0x8048, 0, PLL_CTRL_CLK_CONDC 30 | 31 | /* Run the SPI clock at 104 MHz and EMI at 166 MHz */ 32 | sc_write32 0xd002, 0, PLL_CTRL_CLK_CONDH 33 | 34 | sc_write32 0xb6a0, 0, PLL_CTRL_CLK_CONDC 35 | sc_end 36 | -------------------------------------------------------------------------------- /scriptic/spi-blockmode.S: -------------------------------------------------------------------------------- 1 | #include "scriptic.h" 2 | #include "fernvale-spi.h" 3 | 4 | /* Enable block mode for SPI CS0 */ 5 | sc_new "spi_run", 1, 0, 0 6 | 7 | /* Wait for channel 2 to be idle */ 8 | sc_write32 SPI_CTRL3_CHANNEL2_MASK, SPI_CTRL3_CHANNEL2_MASK, SPI_CTRL3 9 | sc_read32 SPI_CTRL3_CHANNEL2_IDLE, SPI_CTRL3_CHANNEL2_IDLE, SPI_CTRL3 10 | sc_read32 SPI_CTRL1_BUS_IDLE, SPI_CTRL1_BUS_IDLE, SPI_CTRL1 11 | 12 | /* Turn on block mode */ 13 | sc_write32 SPI_BLOCKMODE_ENABLE, SPI_BLOCKMODE_ENABLE, SPI_BLOCKMODE 14 | 15 | /* Trigger the transfer */ 16 | sc_write32 \ 17 | SPI_BLOCKMODE_TRIGGER | SPI_BLOCKMODE_CS0, \ 18 | SPI_BLOCKMODE_TRIGGER | SPI_BLOCKMODE_CS, \ 19 | SPI_BLOCKMODE 20 | 21 | /* Wait for the device to prepare itself */ 22 | sc_read32 SPI_BLOCKMODE_PREP, SPI_BLOCKMODE_PREP, SPI_BLOCKMODE 23 | 24 | /* Wait for it to finish */ 25 | sc_read32 0, SPI_BLOCKMODE_BUSY, SPI_BLOCKMODE 26 | 27 | /* Stop the transfer */ 28 | sc_write32 0, SPI_BLOCKMODE_TRIGGER | SPI_BLOCKMODE_CS, SPI_BLOCKMODE 29 | 30 | /* Wait for it to be disabled */ 31 | sc_read32 0, SPI_BLOCKMODE_PREP, SPI_BLOCKMODE 32 | 33 | /* Exit block mode */ 34 | sc_write32 0, SPI_BLOCKMODE_ENABLE, SPI_BLOCKMODE 35 | 36 | /* Wait for the chip to actually exit block mode */ 37 | sc_read32 0, SPI_BLOCKMODE_ENABLE, SPI_BLOCKMODE 38 | 39 | /* Allow channel 2 to contain data */ 40 | sc_write32 0, SPI_CTRL3_CHANNEL2_MASK, SPI_CTRL3 41 | 42 | sc_end 43 | -------------------------------------------------------------------------------- /scriptic/spi.S: -------------------------------------------------------------------------------- 1 | #include "scriptic.h" 2 | #include "fernvale-spi.h" 3 | #include "fernvale-gpio.h" 4 | 5 | sc_new "spi_init", 1, 0, 0 6 | 7 | /* Ungate the clock */ 8 | sc_write16 0x800, 0x800, 0x80000320 9 | 10 | /* Switch to SPI NOR */ 11 | sc_write16 0, 1, 0x80000230 12 | 13 | /* Remap GPIOs to be SPI */ 14 | sc_write32 \ 15 | GPIO_CTRL_MODE8_IO66_SFCS1 | \ 16 | GPIO_CTRL_MODE8_IO67_SFWP | \ 17 | GPIO_CTRL_MODE8_IO68_SFCS0 | \ 18 | GPIO_CTRL_MODE8_IO69_SFCK | \ 19 | GPIO_CTRL_MODE8_IO70_SFIN | \ 20 | GPIO_CTRL_MODE8_IO71_SFOUT, \ 21 | GPIO_CTRL_MODE8_IO66_MASK | \ 22 | GPIO_CTRL_MODE8_IO67_MASK | \ 23 | GPIO_CTRL_MODE8_IO68_MASK | \ 24 | GPIO_CTRL_MODE8_IO69_MASK | \ 25 | GPIO_CTRL_MODE8_IO70_MASK | \ 26 | GPIO_CTRL_MODE8_IO71_MASK, \ 27 | GPIO_CTRL_MODE8 28 | sc_write32 \ 29 | GPIO_CTRL_MODE9_IO72_SFSHOLD, \ 30 | GPIO_CTRL_MODE9_IO72_MASK, \ 31 | GPIO_CTRL_MODE9 32 | 33 | /* Enable high-impedence for GPIO mode */ 34 | sc_write16 0, \ 35 | GPIO_CTRL_PULL_CTRL1_IO66 | \ 36 | GPIO_CTRL_PULL_CTRL1_IO67 | \ 37 | GPIO_CTRL_PULL_CTRL1_IO72, \ 38 | GPIO_CTRL_RESEN1_R0 39 | sc_write16 0, \ 40 | GPIO_CTRL_PULL_CTRL1_IO66 | \ 41 | GPIO_CTRL_PULL_CTRL1_IO67 | \ 42 | GPIO_CTRL_PULL_CTRL1_IO72, \ 43 | GPIO_CTRL_RESEN1_R1 44 | sc_write16 0, \ 45 | GPIO_CTRL_PULL_CTRL2_IO68 | \ 46 | GPIO_CTRL_PULL_CTRL2_IO69 | \ 47 | GPIO_CTRL_PULL_CTRL2_IO70 | \ 48 | GPIO_CTRL_PULL_CTRL2_IO71, \ 49 | GPIO_CTRL_RESEN2_R0 50 | sc_write16 0, \ 51 | GPIO_CTRL_PULL_CTRL2_IO68 | \ 52 | GPIO_CTRL_PULL_CTRL2_IO69 | \ 53 | GPIO_CTRL_PULL_CTRL2_IO70 | \ 54 | GPIO_CTRL_PULL_CTRL2_IO71, \ 55 | GPIO_CTRL_RESEN2_R1 56 | 57 | sc_end 58 | -------------------------------------------------------------------------------- /serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "serial.h" 3 | #include "memio.h" 4 | 5 | #define FIFO_MAX 1 6 | 7 | #define SERIAL_USB 8 | 9 | #if defined(SERIAL_UART) 10 | 11 | #define UART_IS_DLL 0x100 12 | #define UART_IS_LCR 0x200 13 | 14 | #define UART_RBR 0x00 15 | #define UART_THR 0x00 16 | #define UART_IER 0x04 17 | #define UART_IIR 0x08 18 | #define UART_FCR 0x08 19 | #define UART_LCR 0x0c 20 | #define UART_MCR 0x10 21 | #define UART_LSR 0x14 22 | #define UART_MSR 0x18 23 | #define UART_SCR 0x1c 24 | 25 | #define UART_SPEED 0x24 26 | 27 | /* The following are active when LCR[7] = 1 */ 28 | #define UART_DLL 0x100 29 | #define UART_DLH 0x104 30 | 31 | /* The following are active when LCR = 0xbf */ 32 | #define UART_EFR 0x208 33 | #define UART_XON1 0x210 34 | #define UART_XON2 0x214 35 | #define UART_XOFF1 0x218 36 | #define UART_XOFF2 0x21c 37 | 38 | #define UART_BASE 0xa0080000 39 | 40 | enum uart_baudrate { 41 | UART_38400, 42 | UART_57600, 43 | UART_115200, 44 | UART_230400, 45 | UART_460800, 46 | UART_614400, 47 | UART_921600, 48 | }; 49 | #define UART_BAUD_RATE UART_115200 50 | 51 | /* 52MHz clock input (after PLL init) */ 52 | static const uint16_t divider[] = { 53 | [UART_38400] = 85, 54 | [UART_57600] = 56, 55 | [UART_115200] = 28, 56 | [UART_230400] = 14, 57 | [UART_460800] = 7, 58 | [UART_921600] = 7, /* would need UART_REG(HIGHSPEED) = 1 */ 59 | }; 60 | 61 | static uint8_t uart_getreg(int regnum) 62 | { 63 | volatile uint32_t *reg = (uint32_t *)(UART_BASE + (regnum & 0xff)); 64 | return *reg; 65 | } 66 | 67 | static void uart_setreg(int regnum, uint8_t val) 68 | { 69 | uint8_t old_lcr; 70 | if (regnum & UART_IS_DLL) 71 | uart_setreg(UART_LCR, uart_getreg(UART_LCR) | 0x80); 72 | else if (regnum & UART_IS_LCR) { 73 | old_lcr = uart_getreg(UART_LCR); 74 | uart_setreg(UART_LCR, 0xbf); 75 | } 76 | 77 | volatile uint32_t *reg = (uint32_t *)(UART_BASE + (regnum & 0xff)); 78 | *reg = val; 79 | 80 | if (regnum & UART_IS_DLL) 81 | uart_setreg(UART_LCR, uart_getreg(UART_LCR) & ~0x80); 82 | else if (regnum & UART_IS_LCR) 83 | uart_setreg(UART_LCR, old_lcr); 84 | } 85 | 86 | int serial_putc(uint8_t c) 87 | { 88 | /* Wait for UART to be empty */ 89 | while (! (uart_getreg(UART_LSR) & 0x20)) 90 | asm(""); 91 | 92 | uart_setreg(UART_RBR, c); 93 | return 0; 94 | } 95 | 96 | uint8_t serial_getc(void) 97 | { 98 | while (! (uart_getreg(UART_LSR) & 0x01)) 99 | asm(""); 100 | return uart_getreg(UART_RBR); 101 | } 102 | 103 | /* Return true if there's pending received char */ 104 | int serial_available(void) 105 | { 106 | return uart_getreg(UART_LSR) & 0x01; 107 | } 108 | 109 | int serial_puts(const void *s) 110 | { 111 | const char *str = s; 112 | while(*str) { 113 | if (*str == '\n') 114 | serial_putc('\r'); 115 | serial_putc(*str++); 116 | } 117 | return 0; 118 | } 119 | 120 | int serial_read(void *data, int bytes) 121 | { 122 | while (--bytes) 123 | ((uint8_t *)data++) = serial_getc(); 124 | } 125 | 126 | void serial_init(void) 127 | { 128 | int tmp; 129 | 130 | /* Setup 8-N-1,(UART_WLS_8 | UART_NONE_PARITY | UART_1_STOP) = 0x03 */ 131 | uart_setreg(UART_LCR, 0x03); 132 | 133 | /* Set BaudRate 134 | * config by UART_BAUD_RATE(9:115200) 135 | */ 136 | uart_setreg(UART_DLL, divider[UART_BAUD_RATE]&0xff); 137 | uart_setreg(UART_DLH, divider[UART_BAUD_RATE]>>8); 138 | uart_setreg(UART_LCR, 0x03); 139 | 140 | /* Enable Fifo, and Rx Trigger level = 16bytes, flush Tx, Rx fifo */ 141 | uart_setreg(UART_FCR, 0x47); 142 | 143 | /* DTR , RTS is on, data will be coming, Output2 is high */ 144 | uart_setreg(UART_MCR, 0x03); 145 | 146 | /* Set up normal interrupts */ 147 | uart_setreg(UART_IER, 0x0d); 148 | 149 | /* Pause a while */ 150 | for (tmp=0; tmp<0xff; tmp++); 151 | } 152 | #elif defined(SERIAL_USB) 153 | 154 | #include "fernvale-usb.h" 155 | 156 | static volatile uint8_t *recv_bfr = (uint8_t *)0x70000000; 157 | static int recv_size = 0; 158 | static int recv_offset = 0; 159 | static int send_max = 0; 160 | static int send_cur = 0; 161 | 162 | #define USB_MODE_OUT 0 163 | #define USB_MODE_IN 1 164 | 165 | static void usb_set_mode(uint8_t epnum, int in) 166 | { 167 | writeb(epnum, USB_CTRL_INDEX); 168 | 169 | if (in) { 170 | if (readb(USB_CTRL_EP_INCSR2) & USB_CTRL_EP_INCSR2_MODE) 171 | /* Already set to "IN" */ 172 | return; 173 | 174 | writeb(readb(USB_CTRL_EP_INCSR2) | USB_CTRL_EP_INCSR2_MODE, 175 | USB_CTRL_EP_INCSR2); 176 | } 177 | else { 178 | if (! (readb(USB_CTRL_EP_INCSR2) & USB_CTRL_EP_INCSR2_MODE)) 179 | /* Already set to "OUT" */ 180 | return; 181 | 182 | writeb(readb(USB_CTRL_EP_INCSR2) & ~USB_CTRL_EP_INCSR2_MODE, 183 | USB_CTRL_EP_INCSR2); 184 | } 185 | } 186 | 187 | static void usb_flush_output(int epnum) 188 | { 189 | /* Set endpoint to IN */ 190 | usb_set_mode(epnum, USB_MODE_IN); 191 | 192 | /* Begin transmitting the packet */ 193 | writeb(USB_CTRL_EP_INCSR1_INPKTRDY, USB_CTRL_EP_INCSR1); 194 | 195 | /* Wait for the character to transmit, so we don't double-xmit */ 196 | while (!readb(USB_CTRL_INTRIN)) 197 | asm(""); 198 | 199 | /* Set endpoint back to OUT */ 200 | usb_set_mode(epnum, USB_MODE_OUT); 201 | 202 | send_cur = 0; 203 | } 204 | 205 | static void usb_receive_wait(uint8_t epnum) 206 | { 207 | uint32_t fifo_register = USB_CTRL_EP0_FIFO_DB0 + (epnum * 4); 208 | 209 | /* Wait for data to exist, ignoring other USB IRQs */ 210 | while (!readb(USB_CTRL_INTROUT)) 211 | (void)readb(USB_CTRL_INTRUSB); 212 | 213 | /* Select EP1 */ 214 | writeb(epnum, USB_CTRL_INDEX); 215 | 216 | while (!(readb(USB_CTRL_EP_OUTCSR1) & USB_CTRL_EP_OUTCSR1_RXPKTRDY)) 217 | asm(""); 218 | 219 | recv_size = (readb(USB_CTRL_EP_COUNT1) << 0) & 0x00ff; 220 | recv_size |= (readb(USB_CTRL_EP_COUNT2) << 8) & 0x0300; 221 | recv_offset = 0; 222 | 223 | int bytes_to_read = recv_size + 1; 224 | int off = 0; 225 | 226 | /* Fill in the receive buffer */ 227 | while (bytes_to_read) { 228 | if (bytes_to_read >= 4) { 229 | *((uint32_t *)(recv_bfr + off)) = readl(fifo_register); 230 | bytes_to_read -= 4; 231 | off += 4; 232 | } 233 | else if (bytes_to_read >= 2) { 234 | *((uint16_t *)(recv_bfr + off)) = readw(fifo_register); 235 | bytes_to_read -= 2; 236 | off += 2; 237 | } 238 | else { 239 | *((uint8_t *)(recv_bfr + off)) = readb(fifo_register); 240 | bytes_to_read -= 1; 241 | off += 1; 242 | } 243 | } 244 | 245 | /* Clear FIFO (write 0 to RXPKTRDY) */ 246 | writeb(0, USB_CTRL_EP_OUTCSR1); 247 | } 248 | 249 | static void usb_handle_irqs(int epnum) 250 | { 251 | /* Ignore general-purpose IRQs */ 252 | (void)readb(USB_CTRL_INTRUSB); 253 | 254 | /* Select EP1 */ 255 | writeb(epnum, USB_CTRL_INDEX); 256 | 257 | /* If data exists in the output FIFOs, send the packet */ 258 | if (send_cur) 259 | usb_flush_output(epnum); 260 | 261 | /* If there are incoming bytes, read them into the buffer */ 262 | if (readb(USB_CTRL_EP_OUTCSR1) & USB_CTRL_EP_OUTCSR1_RXPKTRDY) 263 | usb_receive_wait(epnum); 264 | } 265 | 266 | int serial_putc(uint8_t c) 267 | { 268 | /* Add the character to the FIFO */ 269 | writeb(c, USB_CTRL_EP1_FIFO_DB0); 270 | send_cur++; 271 | 272 | if (send_cur >= send_max) 273 | usb_flush_output(1); 274 | 275 | return 0; 276 | } 277 | 278 | uint8_t serial_getc(void) 279 | { 280 | /* Wait for data if the buffer is empty */ 281 | while (!recv_size) 282 | usb_handle_irqs(1); 283 | 284 | recv_size--; 285 | return recv_bfr[recv_offset++]; 286 | } 287 | 288 | int serial_available(void) 289 | { 290 | usb_handle_irqs(1); 291 | return recv_size != 0; 292 | } 293 | 294 | int serial_puts(const void *s) 295 | { 296 | const char *str = s; 297 | while(*str) { 298 | /* Fix up linefeeds */ 299 | if (*str == '\n') 300 | serial_putc('\r'); 301 | 302 | serial_putc(*str++); 303 | } 304 | return 0; 305 | } 306 | 307 | void serial_write(const void *d, int bytes) 308 | { 309 | const char *str = d; 310 | int i; 311 | 312 | for (i = 0; i < bytes; i++) 313 | serial_putc(str[i]); 314 | } 315 | 316 | int serial_read(void *data, int bytes) 317 | { 318 | int i; 319 | for (i = 0; i < bytes; i++) { 320 | *((uint8_t *)data) = serial_getc(); 321 | data++; 322 | } 323 | 324 | return 0; 325 | } 326 | 327 | void serial_init(void) 328 | { 329 | send_max = FIFO_MAX; 330 | send_cur = 0; 331 | 332 | writel(readl(USB_CTRL_CON) | USB_CTRL_CON_NULLPKT_FIX, USB_CTRL_CON); 333 | 334 | (void)readb(USB_CTRL_INTROUT); 335 | (void)readb(USB_CTRL_INTRIN); 336 | (void)readb(USB_CTRL_INTRUSB); 337 | 338 | writeb(0, USB_CTRL_INTROUTE); 339 | (void)readb(USB_CTRL_INTROUTE); 340 | 341 | writeb(0, USB_CTRL_INTRINE); 342 | (void)readb(USB_CTRL_INTRINE); 343 | 344 | writeb(USB_CTRL_INTROUTE_EP1_OUT_ENABLE, USB_CTRL_INTROUTE); 345 | writeb(USB_CTRL_INTRINE_EP1_IN_ENABLE | USB_CTRL_INTRINE_EP0_ENABLE, 346 | USB_CTRL_INTRINE); 347 | 348 | /* Select EP1 */ 349 | writeb(1, USB_CTRL_INDEX); 350 | 351 | /* Make sure the packet size is 64 bytes */ 352 | writeb(send_max, USB_CTRL_EP_INMAXP); 353 | 354 | /* Clear FIFO */ 355 | writeb(USB_CTRL_EP_INCSR1_FLUSHFIFO, USB_CTRL_EP_INCSR1); 356 | 357 | /* Clear the second packet */ 358 | writeb(USB_CTRL_EP_INCSR1_FLUSHFIFO, USB_CTRL_EP_INCSR1); 359 | 360 | /* Set up FIFO to automatically transmit when the buffer is full */ 361 | writeb(0, USB_CTRL_EP_INCSR2); 362 | 363 | /* Set the USB mode to OUT, to ensure we receive packets from host */ 364 | usb_set_mode(1, USB_MODE_OUT); 365 | 366 | recv_offset = 0; 367 | recv_size = 0; 368 | usb_handle_irqs(1); 369 | } 370 | 371 | #else /* SERIAL_USB || SERIAL_UART */ 372 | #error "No serial port defined! Must define SERIAL_USB or SERIAL_UART" 373 | #endif /* SERIAL_USB || SERIAL_UART */ 374 | -------------------------------------------------------------------------------- /sha1.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * sha1.c 4 | * 5 | * Description: 6 | * This file implements the Secure Hashing Algorithm 1 as 7 | * defined in FIPS PUB 180-1 published April 17, 1995. 8 | * 9 | * The SHA-1, produces a 160-bit message digest for a given 10 | * data stream. It should take about 2**n steps to find a 11 | * message with the same digest as a given message and 12 | * 2**(n/2) to find any two messages with the same digest, 13 | * when n is the digest size in bits. Therefore, this 14 | * algorithm can serve as a means of providing a 15 | * "fingerprint" for a message. 16 | * 17 | * Portability Issues: 18 | * SHA-1 is defined in terms of 32-bit "words". This code 19 | * uses (included via "sha1.h" to define 32 and 8 20 | * bit unsigned integer types. If your C compiler does not 21 | * support 32 bit unsigned integers, this code is not 22 | * appropriate. 23 | * 24 | * Caveats: 25 | * SHA-1 is designed to work with messages less than 2^64 bits 26 | * long. Although SHA-1 allows a message digest to be generated 27 | * for messages of any number of bits less than 2^64, this 28 | * implementation only works with messages with a length that is 29 | * a multiple of the size of an 8-bit character. 30 | * 31 | */ 32 | #include "sha1.h" 33 | 34 | /* 35 | * Define the SHA1 circular left shift macro 36 | */ 37 | #define SHA1CircularShift(bits,word) \ 38 | (((word) << (bits)) | ((word) >> (32-(bits)))) 39 | 40 | /* Local Function Prototyptes */ 41 | void SHA1PadMessage(SHA1Context *); 42 | void SHA1ProcessMessageBlock(SHA1Context *); 43 | 44 | /* 45 | * SHA1Reset 46 | * 47 | * Description: 48 | * This function will initialize the SHA1Context in preparation 49 | * for computing a new SHA1 message digest. 50 | * 51 | * Parameters: 52 | * context: [in/out] 53 | * The context to reset. 54 | * 55 | * Returns: 56 | * sha Error Code. 57 | * 58 | */ 59 | int SHA1Reset(SHA1Context *context) 60 | { 61 | if (!context) 62 | { 63 | return shaNull; 64 | } 65 | 66 | context->Length_Low = 0; 67 | context->Length_High = 0; 68 | context->Message_Block_Index = 0; 69 | 70 | context->Intermediate_Hash[0] = 0x67452301; 71 | context->Intermediate_Hash[1] = 0xEFCDAB89; 72 | context->Intermediate_Hash[2] = 0x98BADCFE; 73 | context->Intermediate_Hash[3] = 0x10325476; 74 | context->Intermediate_Hash[4] = 0xC3D2E1F0; 75 | 76 | context->Computed = 0; 77 | context->Corrupted = 0; 78 | 79 | return shaSuccess; 80 | } 81 | 82 | /* 83 | * SHA1Result 84 | * 85 | * Description: 86 | * This function will return the 160-bit message digest into the 87 | * Message_Digest array provided by the caller. 88 | * NOTE: The first octet of hash is stored in the 0th element, 89 | * the last octet of hash in the 19th element. 90 | * 91 | * Parameters: 92 | * context: [in/out] 93 | * The context to use to calculate the SHA-1 hash. 94 | * Message_Digest: [out] 95 | * Where the digest is returned. 96 | * 97 | * Returns: 98 | * sha Error Code. 99 | * 100 | */ 101 | int SHA1Result( SHA1Context *context, 102 | uint8_t Message_Digest[SHA1HashSize]) 103 | { 104 | int i; 105 | 106 | if (!context || !Message_Digest) 107 | { 108 | return shaNull; 109 | } 110 | 111 | if (context->Corrupted) 112 | { 113 | return context->Corrupted; 114 | } 115 | 116 | if (!context->Computed) 117 | { 118 | SHA1PadMessage(context); 119 | for(i=0; i<64; ++i) 120 | { 121 | /* message may be sensitive, clear it out */ 122 | context->Message_Block[i] = 0; 123 | } 124 | context->Length_Low = 0; /* and clear length */ 125 | context->Length_High = 0; 126 | context->Computed = 1; 127 | 128 | 129 | } 130 | 131 | for(i = 0; i < SHA1HashSize; ++i) 132 | { 133 | Message_Digest[i] = context->Intermediate_Hash[i>>2] 134 | >> 8 * ( 3 - ( i & 0x03 ) ); 135 | } 136 | 137 | return shaSuccess; 138 | } 139 | 140 | /* 141 | * SHA1Input 142 | * 143 | * Description: 144 | * This function accepts an array of octets as the next portion 145 | * of the message. 146 | * 147 | * Parameters: 148 | * context: [in/out] 149 | * The SHA context to update 150 | * message_array: [in] 151 | * An array of characters representing the next portion of 152 | * the message. 153 | * length: [in] 154 | * The length of the message in message_array 155 | * 156 | * Returns: 157 | * sha Error Code. 158 | * 159 | */ 160 | int SHA1Input( SHA1Context *context, 161 | const uint8_t *message_array, 162 | unsigned length) 163 | { 164 | if (!length) 165 | { 166 | return shaSuccess; 167 | } 168 | 169 | if (!context || !message_array) 170 | { 171 | return shaNull; 172 | } 173 | 174 | if (context->Computed) 175 | { 176 | context->Corrupted = shaStateError; 177 | 178 | return shaStateError; 179 | } 180 | 181 | if (context->Corrupted) 182 | { 183 | return context->Corrupted; 184 | } 185 | while(length-- && !context->Corrupted) 186 | { 187 | context->Message_Block[context->Message_Block_Index++] = 188 | (*message_array & 0xFF); 189 | 190 | context->Length_Low += 8; 191 | if (context->Length_Low == 0) 192 | { 193 | context->Length_High++; 194 | if (context->Length_High == 0) 195 | { 196 | /* Message is too long */ 197 | context->Corrupted = 1; 198 | } 199 | } 200 | 201 | if (context->Message_Block_Index == 64) 202 | { 203 | SHA1ProcessMessageBlock(context); 204 | } 205 | 206 | message_array++; 207 | } 208 | 209 | return shaSuccess; 210 | } 211 | 212 | /* 213 | * SHA1ProcessMessageBlock 214 | * 215 | * Description: 216 | * This function will process the next 512 bits of the message 217 | * stored in the Message_Block array. 218 | * 219 | * Parameters: 220 | * None. 221 | * 222 | * Returns: 223 | * Nothing. 224 | * 225 | * Comments: 226 | 227 | * Many of the variable names in this code, especially the 228 | * single character names, were used because those were the 229 | * names used in the publication. 230 | * 231 | * 232 | */ 233 | void SHA1ProcessMessageBlock(SHA1Context *context) 234 | { 235 | const uint32_t K[] = { /* Constants defined in SHA-1 */ 236 | 0x5A827999, 237 | 0x6ED9EBA1, 238 | 0x8F1BBCDC, 239 | 0xCA62C1D6 240 | }; 241 | int t; /* Loop counter */ 242 | uint32_t temp; /* Temporary word value */ 243 | uint32_t W[80]; /* Word sequence */ 244 | uint32_t A, B, C, D, E; /* Word buffers */ 245 | 246 | /* 247 | * Initialize the first 16 words in the array W 248 | */ 249 | for(t = 0; t < 16; t++) 250 | { 251 | W[t] = context->Message_Block[t * 4] << 24; 252 | W[t] |= context->Message_Block[t * 4 + 1] << 16; 253 | W[t] |= context->Message_Block[t * 4 + 2] << 8; 254 | W[t] |= context->Message_Block[t * 4 + 3]; 255 | } 256 | 257 | for(t = 16; t < 80; t++) 258 | { 259 | W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 260 | } 261 | 262 | A = context->Intermediate_Hash[0]; 263 | B = context->Intermediate_Hash[1]; 264 | C = context->Intermediate_Hash[2]; 265 | D = context->Intermediate_Hash[3]; 266 | E = context->Intermediate_Hash[4]; 267 | 268 | for(t = 0; t < 20; t++) 269 | { 270 | temp = SHA1CircularShift(5,A) + 271 | ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 272 | E = D; 273 | D = C; 274 | C = SHA1CircularShift(30,B); 275 | B = A; 276 | A = temp; 277 | } 278 | 279 | for(t = 20; t < 40; t++) 280 | { 281 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; 282 | E = D; 283 | D = C; 284 | C = SHA1CircularShift(30,B); 285 | B = A; 286 | A = temp; 287 | } 288 | 289 | for(t = 40; t < 60; t++) 290 | { 291 | temp = SHA1CircularShift(5,A) + 292 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 293 | E = D; 294 | D = C; 295 | C = SHA1CircularShift(30,B); 296 | B = A; 297 | A = temp; 298 | } 299 | 300 | for(t = 60; t < 80; t++) 301 | { 302 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; 303 | E = D; 304 | D = C; 305 | C = SHA1CircularShift(30,B); 306 | B = A; 307 | A = temp; 308 | } 309 | 310 | context->Intermediate_Hash[0] += A; 311 | context->Intermediate_Hash[1] += B; 312 | context->Intermediate_Hash[2] += C; 313 | context->Intermediate_Hash[3] += D; 314 | context->Intermediate_Hash[4] += E; 315 | 316 | context->Message_Block_Index = 0; 317 | } 318 | 319 | 320 | /* 321 | * SHA1PadMessage 322 | * 323 | * Description: 324 | * According to the standard, the message must be padded to an even 325 | * 512 bits. The first padding bit must be a '1'. The last 64 326 | * bits represent the length of the original message. All bits in 327 | * between should be 0. This function will pad the message 328 | * according to those rules by filling the Message_Block array 329 | * accordingly. It will also call the ProcessMessageBlock function 330 | * provided appropriately. When it returns, it can be assumed that 331 | * the message digest has been computed. 332 | * 333 | * Parameters: 334 | * context: [in/out] 335 | * The context to pad 336 | * ProcessMessageBlock: [in] 337 | * The appropriate SHA*ProcessMessageBlock function 338 | * Returns: 339 | * Nothing. 340 | * 341 | */ 342 | 343 | void SHA1PadMessage(SHA1Context *context) 344 | { 345 | /* 346 | * Check to see if the current message block is too small to hold 347 | * the initial padding bits and length. If so, we will pad the 348 | * block, process it, and then continue padding into a second 349 | * block. 350 | */ 351 | if (context->Message_Block_Index > 55) 352 | { 353 | context->Message_Block[context->Message_Block_Index++] = 0x80; 354 | while(context->Message_Block_Index < 64) 355 | { 356 | context->Message_Block[context->Message_Block_Index++] = 0; 357 | } 358 | 359 | SHA1ProcessMessageBlock(context); 360 | 361 | while(context->Message_Block_Index < 56) 362 | { 363 | context->Message_Block[context->Message_Block_Index++] = 0; 364 | } 365 | } 366 | else 367 | { 368 | context->Message_Block[context->Message_Block_Index++] = 0x80; 369 | while(context->Message_Block_Index < 56) 370 | { 371 | context->Message_Block[context->Message_Block_Index++] = 0; 372 | } 373 | } 374 | 375 | /* 376 | * Store the message length as the last 8 octets 377 | */ 378 | context->Message_Block[56] = context->Length_High >> 24; 379 | context->Message_Block[57] = context->Length_High >> 16; 380 | context->Message_Block[58] = context->Length_High >> 8; 381 | context->Message_Block[59] = context->Length_High; 382 | context->Message_Block[60] = context->Length_Low >> 24; 383 | context->Message_Block[61] = context->Length_Low >> 16; 384 | context->Message_Block[62] = context->Length_Low >> 8; 385 | context->Message_Block[63] = context->Length_Low; 386 | 387 | SHA1ProcessMessageBlock(context); 388 | } 389 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.h 3 | * 4 | * Description: 5 | * This is the header file for code which implements the Secure 6 | * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published 7 | * April 17, 1995. 8 | * 9 | * Many of the variable names in this code, especially the 10 | * single character names, were used because those were the names 11 | * used in the publication. 12 | * 13 | * Please read the file sha1.c for more information. 14 | * 15 | */ 16 | #ifndef _SHA1_H_ 17 | #define _SHA1_H_ 18 | 19 | #include 20 | /* 21 | * If you do not have the ISO standard stdint.h header file, then you 22 | * must typdef the following: 23 | * name meaning 24 | * uint32_t unsigned 32 bit integer 25 | * uint8_t unsigned 8 bit integer (i.e., unsigned char) 26 | * int_least16_t integer of >= 16 bits 27 | * 28 | */ 29 | 30 | #ifndef _SHA_enum_ 31 | #define _SHA_enum_ 32 | enum 33 | { 34 | shaSuccess = 0, 35 | shaNull, /* Null pointer parameter */ 36 | shaInputTooLong, /* input data too long */ 37 | shaStateError /* called Input after Result */ 38 | }; 39 | #endif 40 | #define SHA1HashSize 20 41 | 42 | /* 43 | * This structure will hold context information for the SHA-1 44 | * hashing operation 45 | */ 46 | typedef struct SHA1Context 47 | { 48 | uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ 49 | 50 | uint32_t Length_Low; /* Message length in bits */ 51 | uint32_t Length_High; /* Message length in bits */ 52 | 53 | /* Index into message block array */ 54 | int_least16_t Message_Block_Index; 55 | uint8_t Message_Block[64]; /* 512-bit message blocks */ 56 | 57 | int Computed; /* Is the digest computed? */ 58 | int Corrupted; /* Is the message digest corrupted? */ 59 | } SHA1Context; 60 | 61 | /* 62 | * Function Prototypes 63 | */ 64 | 65 | int SHA1Reset( SHA1Context *); 66 | int SHA1Input( SHA1Context *, 67 | const uint8_t *, 68 | unsigned int); 69 | int SHA1Result( SHA1Context *, 70 | uint8_t Message_Digest[SHA1HashSize]); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /spi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "printf.h" 4 | #include "bionic.h" 5 | #include "memio.h" 6 | #include "spi.h" 7 | #include "fernvale-spi.h" 8 | #include "scriptic.h" 9 | 10 | static void spi_init(void) 11 | { 12 | static int spi_initted = 0; 13 | 14 | if (spi_initted) 15 | return; 16 | 17 | spi_initted = 1; 18 | scriptic_run("spi_init"); 19 | } 20 | 21 | int spi_cmd_txrx(uint8_t tx_size, uint8_t rx_size, 22 | uint8_t *tx_buf, uint8_t *rx_buf) 23 | { 24 | spi_init(); 25 | 26 | memcpy(SPI_DATA, tx_buf, tx_size); 27 | 28 | writel(tx_size, SPI_WRITE_COUNT); 29 | writel(rx_size, SPI_READ_COUNT); 30 | 31 | scriptic_run("spi_run"); 32 | 33 | memcpy(rx_buf, SPI_DATA + tx_size, rx_size); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /start.S: -------------------------------------------------------------------------------- 1 | .section vectors 2 | 3 | .global reset 4 | reset: 5 | ldr r0, =0x7000cffc // stack_start 6 | mov sp, r0 7 | mov r2, #0xffffffff 8 | ldr r1, =0x7000c000 // stack_end 9 | 10 | clear_stack: 11 | cmp r1, r0 12 | str r2, [r0] 13 | sub r0, r0, #4 14 | bcc clear_stack 15 | 16 | ## Copy 0x10000 bytes from =spi_offset to psram at 0x3460 17 | #copy_code_to_ram: 18 | # ldr r0, =0x00003460 // Target offset 19 | # ldr r1, =0x10003460 // Source offset 20 | # mov r2, #0x10000 21 | # bl asm_memcpy 22 | # 23 | ## Copy reset vector table to address 0 24 | #copy_reset_vectors: 25 | # mov r0, #0 26 | # ldr r1, =0x3500 27 | # mov r2, #0x100 28 | # bl asm_memcpy 29 | 30 | # Begin executing out of psram 31 | 32 | # Jump to main, which ought to be in psram now 33 | jump_to_main: 34 | ldr r0, =reset_handler 35 | mov pc, r0 36 | 37 | asm_memcpy: 38 | mov r3, r1 39 | add r3, r3, r2 40 | 41 | asm_memcpy_loop: 42 | cmp r1, r3 43 | ldrcc r2, [r1], #4 44 | strcc r2, [r0], #4 45 | bcc asm_memcpy_loop 46 | bx lr 47 | 48 | uart_putc: 49 | ldr r2, =0xa0080014 // uart offset 50 | uart_putc_ready_wait: 51 | ldr r1, [r2] 52 | tst r1, #0x20 53 | beq uart_putc_ready_wait 54 | sub r2, r2, #0x14 55 | str r0, [r2] 56 | bx lr 57 | 58 | .global rv_start 59 | rv_start: 60 | ldr pc, .Lreset_handler 61 | ldr pc, .Lundef_handler 62 | ldr pc, .Lswi_handler 63 | ldr pc, .Lprefetch_abort_handler 64 | ldr pc, .Ldata_abort_handler 65 | ldr pc, .Lreserved_handler 66 | ldr pc, .Lirq_handler 67 | ldr pc, .Lfiq_handler 68 | 69 | .Lreset_handler: 70 | .long reset_handler 71 | .Lundef_handler: 72 | .long undef_handler 73 | .Lswi_handler: 74 | .long swi_handler 75 | .Lprefetch_abort_handler: 76 | .long prefetch_abort_handler 77 | .Ldata_abort_handler: 78 | .long data_abort_handler 79 | .Lreserved_handler: 80 | .long reserved_handler 81 | .Lirq_handler: 82 | .long irq_handler 83 | .Lfiq_handler: 84 | .long fiq_handler 85 | 86 | .global rv_end 87 | rv_end: 88 | 89 | .text 90 | 91 | 92 | .global ram_memcpy 93 | ram_memcpy: 94 | ldr r0, =ram_memcpy_addr 95 | ldr r0, [r0] 96 | mov pc, r0 97 | ram_memcpy_addr: 98 | .long 0x70007388 99 | 100 | .global ram_bzero 101 | ram_bzero: 102 | ldr r0, =ram_bzero_addr 103 | ldr r0, [r0] 104 | mov pc, r0 105 | ram_bzero_addr: 106 | .long 0x700073bc 107 | -------------------------------------------------------------------------------- /usb-loader.S: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | .global _start 4 | _start: 5 | disable_interrupts: 6 | mrs r0, cpsr 7 | mov r1, #0xc0 8 | orr r0, r0, r1 9 | msr cpsr_cxsf, r0 10 | 11 | relocate_stack: 12 | ldr r0, =0x7000bffc // stack_start 13 | mov sp, r0 14 | 15 | print_welcome_banner: 16 | adr r0, welcome_banner 17 | bl uart_puts 18 | 19 | load_program: 20 | adr r0, size_buffer 21 | mov r1, #4 22 | mvn r2, #0 23 | # This function address was discovered by disassembling the ROM, which 24 | # begins around offset 0xfff00000. When the MTK Flash Tool loads code into 25 | # an unflashed MTK chip, it makes calls to a few well-defined positions that 26 | # contain pointers to read a buffer, write a buffer, and flush the current 27 | # write buffer. The programming interface is the same for both USB and 28 | # serial. However, since the MT6260 series of parts primarily boots 29 | # off of USB, we are only interested in the USB thunks. 30 | # The prototype for this function is: 31 | # void usb_uart_read(void *buffer, int bytes, int timeout) 32 | ldr r3, =0xfff03639 33 | blx r3 34 | 35 | ldr r1, size_buffer 36 | 37 | # r1 now contains the number of bytes to load. 38 | # r0 contains the current offset to write to. 39 | # Load bytes from the serial port into RAM. 40 | mov r0, #0x70000000 41 | orr r0, r0, #0x6000 42 | mvn r2, #0 43 | ldr r3, =0xfff03639 44 | blx r3 45 | 46 | jump_to_new_program: 47 | adr r0, launch_message 48 | bl uart_puts 49 | mov r0, #0x70000000 50 | orr r0, r0, #0x6000 51 | mov pc, r0 52 | 53 | .align 4 54 | welcome_banner: .ascii "Fernvale bootloader\r\nWrite four bytes of program " 55 | .asciz "size, then write program data...\r\n>" 56 | launch_message: .asciz "Launching program...\r\n" 57 | size_buffer: .long 0 58 | .align 4 59 | 60 | uart_puts: 61 | push {lr} 62 | mov r3, r0 63 | mov r1, #0 64 | 65 | uart_puts_count_chars_loop: 66 | ldrb r2, [r3], #1 67 | cmp r2, #0 68 | beq uart_puts_print 69 | add r1, r1, #1 70 | b uart_puts_count_chars_loop 71 | uart_puts_print: 72 | mvn r2, #0 73 | 74 | # Call: 75 | # void usb_uart_write(char *data, int bytes, int timeout) 76 | ldr r3, =0xfff03653 77 | blx r3 78 | 79 | # Call: 80 | # void usb_uart_flush(void) 81 | ldr r3, =0xfff04845 82 | blx r3 83 | 84 | uart_puts_exit: 85 | pop {pc} 86 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "serial.h" 3 | #include "printf.h" 4 | 5 | static inline int _isprint(char c) 6 | { 7 | return c > 32 && c < 127; 8 | } 9 | 10 | #define HEX_CHARS "0123456789abcdef" 11 | 12 | void serial_puth(uint32_t pair, int digits) 13 | { 14 | if (digits >= 8) 15 | serial_putc(HEX_CHARS[(pair >> 28) & 0xf]); 16 | if (digits >= 7) 17 | serial_putc(HEX_CHARS[(pair >> 24) & 0xf]); 18 | if (digits >= 6) 19 | serial_putc(HEX_CHARS[(pair >> 20) & 0xf]); 20 | if (digits >= 5) 21 | serial_putc(HEX_CHARS[(pair >> 16) & 0xf]); 22 | if (digits >= 4) 23 | serial_putc(HEX_CHARS[(pair >> 12) & 0xf]); 24 | if (digits >= 3) 25 | serial_putc(HEX_CHARS[(pair >> 8) & 0xf]); 26 | if (digits >= 2) 27 | serial_putc(HEX_CHARS[(pair >> 4) & 0xf]); 28 | if (digits >= 1) 29 | serial_putc(HEX_CHARS[(pair >> 0) & 0xf]); 30 | } 31 | 32 | int serial_print_hex_offset(const void *block, int count, int offset) 33 | { 34 | int byte; 35 | const uint8_t *b = block; 36 | count += offset; 37 | b -= offset; 38 | for ( ; offset < count; offset += 16) { 39 | serial_puth((uint32_t)b + offset, 8); 40 | 41 | for (byte = 0; byte < 16; byte++) { 42 | if (byte == 8) 43 | serial_putc(' '); 44 | serial_putc(' '); 45 | if (offset + byte < count) 46 | serial_puth(b[offset + byte] & 0xff, 2); 47 | else 48 | serial_puts(" "); 49 | } 50 | 51 | serial_puts(" |"); 52 | for (byte = 0; byte < 16 && byte + offset < count; byte++) 53 | serial_putc(_isprint(b[offset + byte]) ? 54 | b[offset + byte] : 55 | '.'); 56 | serial_puts("|\n"); 57 | } 58 | return 0; 59 | } 60 | 61 | int serial_print_hex(const void *block, int count) 62 | { 63 | return serial_print_hex_offset(block, count, 0); 64 | } 65 | 66 | uint32_t __div64_32(uint64_t *n, uint32_t base) 67 | { 68 | uint64_t rem = *n; 69 | uint64_t b = base; 70 | uint64_t res, d = 1; 71 | uint32_t high = rem >> 32; 72 | 73 | /* Reduce the thing a bit first */ 74 | res = 0; 75 | if (high >= base) { 76 | high /= base; 77 | res = (uint64_t) high << 32; 78 | rem -= (uint64_t) (high*base) << 32; 79 | } 80 | 81 | while ((int64_t)b > 0 && b < rem) { 82 | b = b+b; 83 | d = d+d; 84 | } 85 | 86 | do { 87 | if (rem >= b) { 88 | rem -= b; 89 | res += d; 90 | } 91 | b >>= 1; 92 | d >>= 1; 93 | } while (d); 94 | 95 | *n = res; 96 | return rem; 97 | } 98 | 99 | void __div0 (void) 100 | { 101 | printf("Division by 0. Hanging.\n"); 102 | while(1); 103 | } 104 | -------------------------------------------------------------------------------- /vectors.c: -------------------------------------------------------------------------------- 1 | #include "serial.h" 2 | #include "utils.h" 3 | 4 | void reset_handler(void) { 5 | extern int main(int argc, char **argv); 6 | serial_puts("Reset exception\n"); 7 | main(1, 0); 8 | return; 9 | } 10 | 11 | void undef_handler(void) { 12 | serial_puts("Undefined instruction exception\n"); 13 | return; 14 | } 15 | 16 | void swi_handler(void) { 17 | serial_puts("SWI exception\n"); 18 | return; 19 | } 20 | 21 | void prefetch_abort_handler(void) { 22 | serial_puts("Prefetch abort exception\n"); 23 | while(1); 24 | return; 25 | } 26 | 27 | void data_abort_handler(void) { 28 | serial_puts("Data abort exception\n"); 29 | while(1); 30 | return; 31 | } 32 | 33 | void reserved_handler(void) { 34 | serial_puts("Handled some IRQ that shouldn't exist\n"); 35 | while(1); 36 | return; 37 | } 38 | 39 | void irq_handler(void) { 40 | serial_puts("Handling IRQ...\n"); 41 | return; 42 | } 43 | 44 | void fiq_handler(void) { 45 | serial_puts("Handled FIQ\n"); 46 | // while(1); 47 | return; 48 | } 49 | -------------------------------------------------------------------------------- /vsprintf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * linux/lib/vsprintf.c 3 | * 4 | * Copyright (C) 1991, 1992 Linus Torvalds 5 | */ 6 | 7 | /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 8 | /* 9 | * Wirzenius wrote this portably, Torvalds fucked it up :-) 10 | * 11 | * from hush: simple_itoa() was lifted from boa-0.93.15 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "bionic.h" 20 | #include "utils.h" 21 | 22 | # define NUM_TYPE long long 23 | #define noinline __attribute__((noinline)) 24 | 25 | /* some reluctance to put this into a new limits.h, so it is here */ 26 | #define INT_MAX ((int)(~0U>>1)) 27 | 28 | const char hex_asc[] = "0123456789abcdef"; 29 | #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] 30 | #define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] 31 | 32 | static inline char *pack_hex_byte(char *buf, uint8_t byte) 33 | { 34 | *buf++ = hex_asc_hi(byte); 35 | *buf++ = hex_asc_lo(byte); 36 | return buf; 37 | } 38 | 39 | unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) 40 | { 41 | unsigned long result = 0,value; 42 | 43 | if (*cp == '0') { 44 | cp++; 45 | if ((*cp == 'x') && _isxdigit(cp[1])) { 46 | base = 16; 47 | cp++; 48 | } 49 | if (!base) { 50 | base = 8; 51 | } 52 | } 53 | if (!base) { 54 | base = 10; 55 | } 56 | while (_isxdigit(*cp) && (value = _isdigit(*cp) ? *cp-'0' : (_islower(*cp) 57 | ? _toupper(*cp) : *cp)-'A'+10) < base) { 58 | result = result*base + value; 59 | cp++; 60 | } 61 | if (endp) 62 | *endp = (char *)cp; 63 | return result; 64 | } 65 | 66 | int strict_strtoul(const char *cp, unsigned int base, unsigned long *res) 67 | { 68 | char *tail; 69 | unsigned long val; 70 | size_t len; 71 | 72 | *res = 0; 73 | len = _strlen(cp); 74 | if (len == 0) 75 | return -EINVAL; 76 | 77 | val = simple_strtoul(cp, &tail, base); 78 | if (tail == cp) 79 | return -EINVAL; 80 | 81 | if ((*tail == '\0') || 82 | ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { 83 | *res = val; 84 | return 0; 85 | } 86 | 87 | return -EINVAL; 88 | } 89 | 90 | unsigned long strtoul(const char *cp, char **endp, unsigned int base) 91 | { 92 | return simple_strtoul(cp, endp, base); 93 | } 94 | 95 | long simple_strtol(const char *cp,char **endp,unsigned int base) 96 | { 97 | if(*cp=='-') 98 | return -simple_strtoul(cp+1,endp,base); 99 | return simple_strtoul(cp,endp,base); 100 | } 101 | 102 | int ustrtoul(const char *cp, char **endp, unsigned int base) 103 | { 104 | unsigned long result = simple_strtoul(cp, endp, base); 105 | switch (**endp) { 106 | case 'G' : 107 | result *= 1024; 108 | /* fall through */ 109 | case 'M': 110 | result *= 1024; 111 | /* fall through */ 112 | case 'K': 113 | case 'k': 114 | result *= 1024; 115 | if ((*endp)[1] == 'i') { 116 | if ((*endp)[2] == 'B') 117 | (*endp) += 3; 118 | else 119 | (*endp) += 2; 120 | } 121 | } 122 | return result; 123 | } 124 | 125 | unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int base) 126 | { 127 | unsigned long long result = 0, value; 128 | 129 | if (*cp == '0') { 130 | cp++; 131 | if ((*cp == 'x') && _isxdigit (cp[1])) { 132 | base = 16; 133 | cp++; 134 | } 135 | if (!base) { 136 | base = 8; 137 | } 138 | } 139 | if (!base) { 140 | base = 10; 141 | } 142 | while (_isxdigit (*cp) && (value = _isdigit (*cp) 143 | ? *cp - '0' 144 | : (_islower (*cp) ? _toupper (*cp) : *cp) - 'A' + 10) < base) { 145 | result = result * base + value; 146 | cp++; 147 | } 148 | if (endp) 149 | *endp = (char *) cp; 150 | return result; 151 | } 152 | 153 | /* we use this so that we can do without the ctype library */ 154 | #define is_digit(c) ((c) >= '0' && (c) <= '9') 155 | 156 | static int skip_atoi(const char **s) 157 | { 158 | int i=0; 159 | 160 | while (is_digit(**s)) 161 | i = i*10 + *((*s)++) - '0'; 162 | return i; 163 | } 164 | 165 | /* Decimal conversion is by far the most typical, and is used 166 | * for /proc and /sys data. This directly impacts e.g. top performance 167 | * with many processes running. We optimize it for speed 168 | * using code from 169 | * http://www.cs.uiowa.edu/~jones/bcd/decimal.html 170 | * (with permission from the author, Douglas W. Jones). */ 171 | 172 | /* Formats correctly any integer in [0,99999]. 173 | * Outputs from one to five digits depending on input. 174 | * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ 175 | static char* put_dec_trunc(char *buf, unsigned q) 176 | { 177 | unsigned d3, d2, d1, d0; 178 | d1 = (q>>4) & 0xf; 179 | d2 = (q>>8) & 0xf; 180 | d3 = (q>>12); 181 | 182 | d0 = 6*(d3 + d2 + d1) + (q & 0xf); 183 | q = (d0 * 0xcd) >> 11; 184 | d0 = d0 - 10*q; 185 | *buf++ = d0 + '0'; /* least significant digit */ 186 | d1 = q + 9*d3 + 5*d2 + d1; 187 | if (d1 != 0) { 188 | q = (d1 * 0xcd) >> 11; 189 | d1 = d1 - 10*q; 190 | *buf++ = d1 + '0'; /* next digit */ 191 | 192 | d2 = q + 2*d2; 193 | if ((d2 != 0) || (d3 != 0)) { 194 | q = (d2 * 0xd) >> 7; 195 | d2 = d2 - 10*q; 196 | *buf++ = d2 + '0'; /* next digit */ 197 | 198 | d3 = q + 4*d3; 199 | if (d3 != 0) { 200 | q = (d3 * 0xcd) >> 11; 201 | d3 = d3 - 10*q; 202 | *buf++ = d3 + '0'; /* next digit */ 203 | if (q != 0) 204 | *buf++ = q + '0'; /* most sign. digit */ 205 | } 206 | } 207 | } 208 | return buf; 209 | } 210 | /* Same with if's removed. Always emits five digits */ 211 | static char* put_dec_full(char *buf, unsigned q) 212 | { 213 | /* BTW, if q is in [0,9999], 8-bit ints will be enough, */ 214 | /* but anyway, gcc produces better code with full-sized ints */ 215 | unsigned d3, d2, d1, d0; 216 | d1 = (q>>4) & 0xf; 217 | d2 = (q>>8) & 0xf; 218 | d3 = (q>>12); 219 | 220 | /* 221 | * Possible ways to approx. divide by 10 222 | * gcc -O2 replaces multiply with shifts and adds 223 | * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386) 224 | * (x * 0x67) >> 10: 1100111 225 | * (x * 0x34) >> 9: 110100 - same 226 | * (x * 0x1a) >> 8: 11010 - same 227 | * (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) 228 | */ 229 | 230 | d0 = 6*(d3 + d2 + d1) + (q & 0xf); 231 | q = (d0 * 0xcd) >> 11; 232 | d0 = d0 - 10*q; 233 | *buf++ = d0 + '0'; 234 | d1 = q + 9*d3 + 5*d2 + d1; 235 | q = (d1 * 0xcd) >> 11; 236 | d1 = d1 - 10*q; 237 | *buf++ = d1 + '0'; 238 | 239 | d2 = q + 2*d2; 240 | q = (d2 * 0xd) >> 7; 241 | d2 = d2 - 10*q; 242 | *buf++ = d2 + '0'; 243 | 244 | d3 = q + 4*d3; 245 | q = (d3 * 0xcd) >> 11; /* - shorter code */ 246 | /* q = (d3 * 0x67) >> 10; - would also work */ 247 | d3 = d3 - 10*q; 248 | *buf++ = d3 + '0'; 249 | *buf++ = q + '0'; 250 | return buf; 251 | } 252 | /* No inlining helps gcc to use registers better */ 253 | static noinline char* put_dec(char *buf, unsigned NUM_TYPE num) 254 | { 255 | while (1) { 256 | unsigned rem; 257 | if (num < 100000) 258 | return put_dec_trunc(buf, num); 259 | rem = do_div(num, 100000); 260 | buf = put_dec_full(buf, rem); 261 | } 262 | } 263 | 264 | #define ZEROPAD 1 /* pad with zero */ 265 | #define SIGN 2 /* unsigned/signed long */ 266 | #define PLUS 4 /* show plus */ 267 | #define SPACE 8 /* space if plus */ 268 | #define LEFT 16 /* left justified */ 269 | #define SMALL 32 /* Must be 32 == 0x20 */ 270 | #define SPECIAL 64 /* 0x */ 271 | 272 | /* 273 | * Macro to add a new character to our output string, but only if it will 274 | * fit. The macro moves to the next character position in the output string. 275 | */ 276 | #define ADDCH(str, ch) do { \ 277 | if ((str) < end) \ 278 | *(str) = (ch); \ 279 | ++str; \ 280 | } while (0) 281 | 282 | static char *number(char *buf, char *end, unsigned NUM_TYPE num, 283 | int base, int size, int precision, int type) 284 | { 285 | /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 286 | static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 287 | 288 | char tmp[66]; 289 | char sign; 290 | char locase; 291 | int need_pfx = ((type & SPECIAL) && base != 10); 292 | int i; 293 | 294 | /* locase = 0 or 0x20. ORing digits or letters with 'locase' 295 | * produces same digits or (maybe lowercased) letters */ 296 | locase = (type & SMALL); 297 | if (type & LEFT) 298 | type &= ~ZEROPAD; 299 | sign = 0; 300 | if (type & SIGN) { 301 | if ((signed NUM_TYPE) num < 0) { 302 | sign = '-'; 303 | num = - (signed NUM_TYPE) num; 304 | size--; 305 | } else if (type & PLUS) { 306 | sign = '+'; 307 | size--; 308 | } else if (type & SPACE) { 309 | sign = ' '; 310 | size--; 311 | } 312 | } 313 | if (need_pfx) { 314 | size--; 315 | if (base == 16) 316 | size--; 317 | } 318 | 319 | /* generate full string in tmp[], in reverse order */ 320 | i = 0; 321 | if (num == 0) 322 | tmp[i++] = '0'; 323 | /* Generic code, for any base: 324 | else do { 325 | tmp[i++] = (digits[do_div(num,base)] | locase); 326 | } while (num != 0); 327 | */ 328 | else if (base != 10) { /* 8 or 16 */ 329 | int mask = base - 1; 330 | int shift = 3; 331 | if (base == 16) shift = 4; 332 | do { 333 | tmp[i++] = (digits[((unsigned char)num) & mask] | locase); 334 | num >>= shift; 335 | } while (num); 336 | } else { /* base 10 */ 337 | i = put_dec(tmp, num) - tmp; 338 | } 339 | 340 | /* printing 100 using %2d gives "100", not "00" */ 341 | if (i > precision) 342 | precision = i; 343 | /* leading space padding */ 344 | size -= precision; 345 | if (!(type & (ZEROPAD + LEFT))) { 346 | while (--size >= 0) 347 | ADDCH(buf, ' '); 348 | } 349 | /* sign */ 350 | if (sign) 351 | ADDCH(buf, sign); 352 | /* "0x" / "0" prefix */ 353 | if (need_pfx) { 354 | ADDCH(buf, '0'); 355 | if (base == 16) 356 | ADDCH(buf, 'X' | locase); 357 | } 358 | /* zero or space padding */ 359 | if (!(type & LEFT)) { 360 | char c = (type & ZEROPAD) ? '0' : ' '; 361 | 362 | while (--size >= 0) 363 | ADDCH(buf, c); 364 | } 365 | /* hmm even more zero padding? */ 366 | while (i <= --precision) 367 | ADDCH(buf, '0'); 368 | /* actual digits of result */ 369 | while (--i >= 0) 370 | ADDCH(buf, tmp[i]); 371 | /* trailing space padding */ 372 | while (--size >= 0) 373 | ADDCH(buf, ' '); 374 | return buf; 375 | } 376 | 377 | static char *string(char *buf, char *end, char *s, int field_width, 378 | int precision, int flags) 379 | { 380 | int len, i; 381 | 382 | if (s == 0) 383 | s = "(null)"; 384 | 385 | len = _strnlen(s, precision) - 1; 386 | 387 | if (!(flags & LEFT)) 388 | while (len < field_width--) 389 | ADDCH(buf, ' '); 390 | for (i = 0; i < len; ++i) 391 | ADDCH(buf, *s++); 392 | while (len < field_width--) 393 | ADDCH(buf, ' '); 394 | return buf; 395 | } 396 | 397 | #ifdef CONFIG_CMD_NET 398 | static char *mac_address_string(char *buf, char *end, uint8_t *addr, int field_width, 399 | int precision, int flags) 400 | { 401 | char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ 402 | char *p = mac_addr; 403 | int i; 404 | 405 | for (i = 0; i < 6; i++) { 406 | p = pack_hex_byte(p, addr[i]); 407 | if (!(flags & SPECIAL) && i != 5) 408 | *p++ = ':'; 409 | } 410 | *p = '\0'; 411 | 412 | return string(buf, end, mac_addr, field_width, precision, 413 | flags & ~SPECIAL); 414 | } 415 | 416 | static char *ip6_addr_string(char *buf, char *end, uint8_t *addr, int field_width, 417 | int precision, int flags) 418 | { 419 | char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */ 420 | char *p = ip6_addr; 421 | int i; 422 | 423 | for (i = 0; i < 8; i++) { 424 | p = pack_hex_byte(p, addr[2 * i]); 425 | p = pack_hex_byte(p, addr[2 * i + 1]); 426 | if (!(flags & SPECIAL) && i != 7) 427 | *p++ = ':'; 428 | } 429 | *p = '\0'; 430 | 431 | return string(buf, end, ip6_addr, field_width, precision, 432 | flags & ~SPECIAL); 433 | } 434 | 435 | static char *ip4_addr_string(char *buf, char *end, uint8_t *addr, int field_width, 436 | int precision, int flags) 437 | { 438 | char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ 439 | char temp[3]; /* hold each IP quad in reverse order */ 440 | char *p = ip4_addr; 441 | int i, digits; 442 | 443 | for (i = 0; i < 4; i++) { 444 | digits = put_dec_trunc(temp, addr[i]) - temp; 445 | /* reverse the digits in the quad */ 446 | while (digits--) 447 | *p++ = temp[digits]; 448 | if (i != 3) 449 | *p++ = '.'; 450 | } 451 | *p = '\0'; 452 | 453 | return string(buf, end, ip4_addr, field_width, precision, 454 | flags & ~SPECIAL); 455 | } 456 | #endif 457 | 458 | /* 459 | * Show a '%p' thing. A kernel extension is that the '%p' is followed 460 | * by an extra set of alphanumeric characters that are extended format 461 | * specifiers. 462 | * 463 | * Right now we handle: 464 | * 465 | * - 'M' For a 6-byte MAC address, it prints the address in the 466 | * usual colon-separated hex notation 467 | * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated 468 | * decimal for v4 and colon separated network-order 16 bit hex for v6) 469 | * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is 470 | * currently the same 471 | * 472 | * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 473 | * function pointers are really function descriptors, which contain a 474 | * pointer to the real address. 475 | */ 476 | static char *pointer(const char *fmt, char *buf, char *end, void *ptr, 477 | int field_width, int precision, int flags) 478 | { 479 | if (!ptr) 480 | return string(buf, end, "(null)", field_width, precision, 481 | flags); 482 | 483 | #ifdef CONFIG_CMD_NET 484 | switch (*fmt) { 485 | case 'm': 486 | flags |= SPECIAL; 487 | /* Fallthrough */ 488 | case 'M': 489 | return mac_address_string(buf, end, ptr, field_width, 490 | precision, flags); 491 | case 'i': 492 | flags |= SPECIAL; 493 | /* Fallthrough */ 494 | case 'I': 495 | if (fmt[1] == '6') 496 | return ip6_addr_string(buf, end, ptr, field_width, 497 | precision, flags); 498 | if (fmt[1] == '4') 499 | return ip4_addr_string(buf, end, ptr, field_width, 500 | precision, flags); 501 | flags &= ~SPECIAL; 502 | break; 503 | } 504 | #endif 505 | flags |= SMALL; 506 | if (field_width == -1) { 507 | field_width = 2*sizeof(void *); 508 | flags |= ZEROPAD; 509 | } 510 | return number(buf, end, (unsigned long)ptr, 16, field_width, 511 | precision, flags); 512 | } 513 | 514 | static int vsnprintf_internal(char *buf, size_t size, const char *fmt, 515 | va_list args) 516 | { 517 | unsigned NUM_TYPE num; 518 | int base; 519 | char *str; 520 | 521 | int flags; /* flags to number() */ 522 | 523 | int field_width; /* width of output field */ 524 | int precision; /* min. # of digits for integers; max 525 | number of chars for from string */ 526 | int qualifier; /* 'h', 'l', or 'L' for integer fields */ 527 | /* 'z' support added 23/7/1999 S.H. */ 528 | /* 'z' changed to 'Z' --davidm 1/25/99 */ 529 | /* 't' added for ptrdiff_t */ 530 | char *end = buf + size; 531 | 532 | str = buf; 533 | 534 | for (; *fmt ; ++fmt) { 535 | if (*fmt == '\n') { 536 | ADDCH(str, '\r'); 537 | ADDCH(str, '\n'); 538 | continue; 539 | } 540 | else if (*fmt != '%') { 541 | ADDCH(str, *fmt); 542 | continue; 543 | } 544 | 545 | /* process flags */ 546 | flags = 0; 547 | repeat: 548 | ++fmt; /* this also skips first '%' */ 549 | switch (*fmt) { 550 | case '-': flags |= LEFT; goto repeat; 551 | case '+': flags |= PLUS; goto repeat; 552 | case ' ': flags |= SPACE; goto repeat; 553 | case '#': flags |= SPECIAL; goto repeat; 554 | case '0': flags |= ZEROPAD; goto repeat; 555 | } 556 | 557 | /* get field width */ 558 | field_width = -1; 559 | if (is_digit(*fmt)) 560 | field_width = skip_atoi(&fmt); 561 | else if (*fmt == '*') { 562 | ++fmt; 563 | /* it's the next argument */ 564 | field_width = va_arg(args, int); 565 | if (field_width < 0) { 566 | field_width = -field_width; 567 | flags |= LEFT; 568 | } 569 | } 570 | 571 | /* get the precision */ 572 | precision = -1; 573 | if (*fmt == '.') { 574 | ++fmt; 575 | if (is_digit(*fmt)) 576 | precision = skip_atoi(&fmt); 577 | else if (*fmt == '*') { 578 | ++fmt; 579 | /* it's the next argument */ 580 | precision = va_arg(args, int); 581 | } 582 | if (precision < 0) 583 | precision = 0; 584 | } 585 | 586 | /* get the conversion qualifier */ 587 | qualifier = -1; 588 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || 589 | *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { 590 | qualifier = *fmt; 591 | ++fmt; 592 | if (qualifier == 'l' && *fmt == 'l') { 593 | qualifier = 'L'; 594 | ++fmt; 595 | } 596 | } 597 | 598 | /* default base */ 599 | base = 10; 600 | 601 | switch (*fmt) { 602 | case 'c': 603 | if (!(flags & LEFT)) { 604 | while (--field_width > 0) 605 | ADDCH(str, ' '); 606 | } 607 | ADDCH(str, (unsigned char) va_arg(args, int)); 608 | while (--field_width > 0) 609 | ADDCH(str, ' '); 610 | continue; 611 | 612 | case 's': 613 | str = string(str, end, va_arg(args, char *), 614 | field_width, precision, flags); 615 | continue; 616 | 617 | case 'p': 618 | str = pointer(fmt+1, str, end, 619 | va_arg(args, void *), 620 | field_width, precision, flags); 621 | /* Skip all alphanumeric pointer suffixes */ 622 | while (_isalnum(fmt[1])) 623 | fmt++; 624 | continue; 625 | 626 | case 'n': 627 | if (qualifier == 'l') { 628 | long * ip = va_arg(args, long *); 629 | *ip = (str - buf); 630 | } else { 631 | int * ip = va_arg(args, int *); 632 | *ip = (str - buf); 633 | } 634 | continue; 635 | 636 | case '%': 637 | ADDCH(str, '%'); 638 | continue; 639 | 640 | /* integer number formats - set up the flags and "break" */ 641 | case 'o': 642 | base = 8; 643 | break; 644 | 645 | case 'x': 646 | flags |= SMALL; 647 | case 'X': 648 | base = 16; 649 | break; 650 | 651 | case 'd': 652 | case 'i': 653 | flags |= SIGN; 654 | case 'u': 655 | break; 656 | 657 | default: 658 | ADDCH(str, '%'); 659 | if (*fmt) 660 | ADDCH(str, *fmt); 661 | else 662 | --fmt; 663 | continue; 664 | } 665 | if (qualifier == 'L') /* "quad" for 64 bit variables */ 666 | num = va_arg(args, unsigned long long); 667 | else if (qualifier == 'l') { 668 | num = va_arg(args, unsigned long); 669 | if (flags & SIGN) 670 | num = (signed long) num; 671 | } else if (qualifier == 'Z' || qualifier == 'z') { 672 | num = va_arg(args, size_t); 673 | } else if (qualifier == 't') { 674 | num = (unsigned long) va_arg(args, void *); 675 | } else if (qualifier == 'h') { 676 | num = (unsigned short) va_arg(args, int); 677 | if (flags & SIGN) 678 | num = (signed short) num; 679 | } else { 680 | num = va_arg(args, unsigned int); 681 | if (flags & SIGN) 682 | num = (signed int) num; 683 | } 684 | str = number(str, end, num, base, field_width, precision, 685 | flags); 686 | } 687 | 688 | if (size > 0) { 689 | ADDCH(str, '\0'); 690 | if (str > end) 691 | end[-1] = '\0'; 692 | } 693 | /* the trailing null byte doesn't count towards the total */ 694 | return str-buf; 695 | } 696 | 697 | int vsnprintf(char *buf, size_t size, const char *fmt, 698 | va_list args) 699 | { 700 | return vsnprintf_internal(buf, size, fmt, args); 701 | } 702 | 703 | int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) 704 | { 705 | int i; 706 | 707 | i = vsnprintf(buf, size, fmt, args); 708 | 709 | if (i < size) 710 | return i; 711 | if (size != 0) 712 | return size - 1; 713 | return 0; 714 | } 715 | 716 | int snprintf(char *buf, size_t size, const char *fmt, ...) 717 | { 718 | va_list args; 719 | int i; 720 | 721 | va_start(args, fmt); 722 | i = vsnprintf(buf, size, fmt, args); 723 | va_end(args); 724 | 725 | return i; 726 | } 727 | 728 | int scnprintf(char *buf, size_t size, const char *fmt, ...) 729 | { 730 | va_list args; 731 | int i; 732 | 733 | va_start(args, fmt); 734 | i = vscnprintf(buf, size, fmt, args); 735 | va_end(args); 736 | 737 | return i; 738 | } 739 | 740 | /** 741 | * Format a string and place it in a buffer (va_list version) 742 | * 743 | * @param buf The buffer to place the result into 744 | * @param fmt The format string to use 745 | * @param args Arguments for the format string 746 | * 747 | * The function returns the number of characters written 748 | * into @buf. Use vsnprintf() or vscnprintf() in order to avoid 749 | * buffer overflows. 750 | * 751 | * If you're not already dealing with a va_list consider using sprintf(). 752 | */ 753 | int vsprintf(char *buf, const char *fmt, va_list args) 754 | { 755 | return vsnprintf_internal(buf, INT_MAX, fmt, args); 756 | } 757 | 758 | int sprintf(char * buf, const char *fmt, ...) 759 | { 760 | va_list args; 761 | int i; 762 | 763 | va_start(args, fmt); 764 | i = vsprintf(buf,fmt,args); 765 | va_end(args); 766 | return i; 767 | } 768 | 769 | extern void serial_puts(const char *bfr); 770 | 771 | int printf(const char *fmt, ...) 772 | { 773 | va_list args; 774 | int i; 775 | char printbuffer[256]; 776 | 777 | va_start(args, fmt); 778 | i = vsnprintf_internal(printbuffer, sizeof(printbuffer), fmt, args); 779 | va_end(args); 780 | serial_puts(printbuffer); 781 | 782 | return i; 783 | } 784 | 785 | char *simple_itoa(uint32_t i) 786 | { 787 | /* 21 digits plus null terminator, good for 64-bit or smaller ints */ 788 | static char local[22]; 789 | char *p = &local[21]; 790 | 791 | *p-- = '\0'; 792 | do { 793 | *p-- = '0' + i % 10; 794 | i /= 10; 795 | } while (i > 0); 796 | return p + 1; 797 | } 798 | --------------------------------------------------------------------------------