Files
mtboss/research/FLASHING_ALGORITHM.md
T
2026-08-03 19:57:38 +03:00

196 lines
9.6 KiB
Markdown

# MTBoss: MT6261 Direct BootROM SPI NOR Flashing Algorithm
Thorough technical documentation of the BROM-direct SPI NOR flash programming algorithm for MediaTek MT6261 series feature phones (such as the Maxcom MM817).
This approach bypasses Download Agent (DA) binaries entirely by manipulating the hardware Serial Flash Interface (SFI) controller directly via BootROM register access commands.
---
## 1. Overview & Architecture
Standard MediaTek flashing workflows load a two-stage Download Agent (DA) into SRAM (`0x70007000`) and DRAM (`0x10020000`) via BootROM commands `0xD7` and `0xD5`. However, on many legacy feature phone platforms, standard DA binaries silently crash or fail to execute due to uninitialized DRAM or memory map mismatches.
This algorithm implements **Direct BootROM SFI Hardware Flashing**:
* **Handshake & Register Initialization**: Connects via native BootROM serial protocol, disables system/battery watchdogs, and enables USB download mode.
* **Direct Hardware SFI Controller Manipulation**: Uses BROM 32-bit memory access commands (`0xD1` / `0xD4`) to control the Serial Flash Interface (`0xA0140000`).
* **Hardware MAC Controller Switching**: Enables SFI MAC Mode (`SFI_MAC_SEL`) to send raw SPI NOR commands (WREN `0x06`, Sector Erase `0x20`, Page Program `0x02`, Read Status `0x05`, Read JEDEC ID `0x9F`) directly to the physical NOR flash chip.
* **Buffer Management**: Chunks page program payloads to **64 bytes** to strictly fit within the 160-byte (`0x00A0`) `SFI_GPRAM` hardware buffer limit.
* **Memory-Mapped Verification**: Uses BROM 32-bit read commands (`0xD1`) at Memory Map Mode 2 (`0xA0510000 = 2`) to perform byte-for-byte readback verification.
---
## 2. Hardware Memory & Register Map
### 2.1 Base Addresses
| Peripheral | Base Address | Description |
| :--- | :--- | :--- |
| **SFI_BASE** | `0xA0140000` | Serial Flash Interface Registers |
| **CONFIG_BASE** | `0xA0010000` | Clock & System Configuration Registers |
| **RGU_BASE** | `0xA0030000` | Reset Generation Unit (Watchdog) |
| **BOOT_ENG_BASE** | `0xA0510000` | Boot Engine Configuration |
| **PMU_BASE** | `0xA0700000` | Power Management Unit |
### 2.2 SFI Registers (`0xA0140000`)
| Offset | Name | Bitfield / Description |
| :--- | :--- | :--- |
| `+0x0000` | `SFI_MAC_CTL` | Bit 0: `SFI_WIP` (Write In Progress)<br>Bit 1: `SFI_WIP_READY` (Trigger Completed)<br>Bit 2: `SFI_TRIG` (Trigger MAC Operation)<br>Bit 3: `SFI_MAC_EN` (Enable MAC Controller)<br>Bit 4: `SFI_MAC_SIO_SEL` (Serial I/O Select)<br>Bit 16: `SFI_RELEASE_MAC` (Release MAC Mode)<br>Bit 28: `SFI_MAC_SEL` (Route SPI Bus to MAC Controller) |
| `+0x0004` | `SFI_DIRECT_CTL` | Direct Read Controller Configuration |
| `+0x0008` | `SFI_MISC_CTL` | Bit 8: `SFI_REQ_IDLE`<br>Bit 9: `SFI_BOOT_REMAP`<br>Bit 23: `SFI_NO_RELOAD` |
| `+0x0010` | `SFI_MAC_OUTL` | Outgoing Command/Data Length (in bytes) |
| `+0x0014` | `SFI_MAC_INL` | Incoming Data Length to read (in bytes) |
| `+0x0044` | `SFI_MISC_CTL3` | Bit 9: `SFI_CH2_TRANS_MASK` (AHB Channel Mask)<br>Bit 13: `SFI_CH2_TRANS_IDLE` |
| `+0x0800` | `SFI_GPRAM` | General Purpose RAM Buffer (160 bytes total, `0x0800 - 0x08A0`) |
---
## 3. Step-by-Step Flashing Algorithm
```mermaid
flowchart TD
A["Start: Connect Port (rtscts=True)"] --> B["BROM Sync: Send 0xA0 (wait 0x5F)<br>Send 0x0A5005 (wait 0xF5AFFA)"]
B --> C["Read Chip ID (0xA2 to 0x80000008)"]
C --> D["Disable Watchdogs & Set Boot Map Mode 2"]
D --> E["Unlock SPI Flash Write Protection"]
E --> F["Erase 4KB Sectors via SFI MAC (0x20)"]
F --> G["Program Pages via SFI MAC (0x02)<br>(64-byte chunks to fit GPRAM)"]
G --> H["Read Back & Verify via BROM 0xD1"]
H --> I["Reset Device (0xA003001C = 0x1209)"]
```
### Step 1: BootROM Serial Connection & Handshake
1. Open serial port with **`rtscts=True`** and **`dsrdtr=True`** at 115200 baud.
2. Send single sync byte `0xA0` repeatedly until `0x5F` is received.
3. Send 3-byte command packet `b'\x0A\x50\x05'`.
4. Verify receive 3-byte ACK packet `b'\xF5\xAF\xFA'`.
### Step 2: Chip Identification & Watchdog Disabling
1. Read Chip ID via 16-bit BROM read command `0xA2`:
- Send `b'\xA2' + struct.pack('>II', 0x80000008, 1)`
- Receive echo and 2-byte response (`0x6261` = MT6261).
2. Disable watchdogs and configure power registers via 16-bit BROM write command `0xD2`:
- `0xA0030000 = 0x2200` (Disable system watchdog)
- `0xA0700A28 = 0x8000` (Enable USB download mode)
- `0xA0700A24 = 0x0002` (Disable battery watchdog)
### Step 3: Configure Memory Mapping Mode 2
1. Set boot engine memory map mode to Mode 2 via 32-bit BROM write command `0xD4`:
- Send `b'\xD4' + struct.pack('>II', 0xA0510000, 1)` + `struct.pack('>I', 2)`
- Maps physical SPI NOR flash starting at CPU address `0x00000000`.
### Step 4: SPI NOR Status Register Inspection & Unlock
1. Read SPI NOR Status Register (`0x05`) via `sfi_mac_cmd_read(0x05, 1)`.
2. Inspect Block Protect bits (`BP0`, `BP1`, `BP2`, `BP3`).
3. If protected, issue status register unlock:
- Send Volatile Write Enable `0x50` via `sfi_mac_cmd_write(0x50)`.
- Send Write Status Register `0x01` with data `0x00` via `sfi_mac_cmd_write(0x01, data=b'\x00')`.
### Step 5: SFI Hardware MAC Mode Register Sequencing
All SPI NOR operations (Erase, Program, Status Read) must follow this exact register sequence:
```python
# 1. Format payload: [cmd_byte] + [3-byte big-endian address] + [optional payload data]
payload = bytes([cmd_byte])
if addr is not None:
payload += addr.to_bytes(3, 'big')
payload += data
total_len = len(payload)
# 2. Write payload into SFI GPRAM (0xA0140800) in 32-bit little-endian words
for i in range(0, total_len, 4):
chunk = payload[i : i + 4]
val = int.from_bytes(chunk.ljust(4, b'\x00'), 'little')
write_reg32(0xA0140800 + i, val)
# 3. Mask AHB Channel 2 in MISC_CTL3 (0xA0140044)
write_reg32(0xA0140044, read_reg32(0xA0140044) | (1 << 9))
# 4. Enable MAC mode FIRST (SFI_MAC_SEL bit 28 | SFI_MAC_EN bit 3)
mac_val = (1 << 28) | (1 << 3)
write_reg32(0xA0140000, mac_val)
# 5. Set OUTL and INL lengths WHILE MAC mode is active
write_reg32(0xA0140010, total_len) # SFI_MAC_OUTL
write_reg32(0xA0140014, 0) # SFI_MAC_INL
# 6. Trigger transaction by adding SFI_TRIG (bit 2)
write_reg32(0xA0140000, mac_val | (1 << 2))
# 7. Poll SFI_MAC_CTL until SFI_WIP_READY (bit 1) is 1 and SFI_WIP (bit 0) is 0
while True:
v = read_reg32(0xA0140000)
if (v & 0x02) and not (v & 0x01):
break
# 8. Clean up MAC mode and unmask AHB channel 2
write_reg32(0xA0140000, 0)
write_reg32(0xA0140044, read_reg32(0xA0140044) & ~(1 << 9))
```
> [!CRITICAL]
> **Register Order Dependency**: Step 3 (`SFI_MAC_CTL` enable) MUST occur BEFORE Step 4 (`SFI_MAC_OUTL` set). Writing to `SFI_MAC_OUTL` while MAC mode is disabled will cause the controller to ignore the transfer length and transmit 0 payload bytes.
### Step 6: Sector Erasing (4KB Sectors)
For each 4KB boundary (`0x0000`, `0x1000`, `0x2000`, `0x3000`):
1. Send Write Enable (`0x06`) via `sfi_mac_cmd_write(0x06)`.
2. Issue Sector Erase (`0x20`) with target address:
- `sfi_mac_cmd_write(0x20, addr=sector_address)`
3. Wait until flash WIP bit clears in status register (`0x05`).
### Step 7: Chunked Page Programming
SPI NOR page programming uses command `0x02`.
Because `SFI_GPRAM` is limited to **160 bytes** (`0x0800 - 0x08A0`), page data MUST be chunked into maximum **64 bytes** per command:
1. Divide target page payload into 64-byte chunks.
2. For each 64-byte chunk:
- Send Write Enable (`0x06`).
- Issue Page Program (`0x02`) with current chunk address and 64-byte payload:
`sfi_mac_cmd_write(0x02, addr=curr_addr, data=64_byte_chunk)`
- Wait until flash WIP bit clears in status register (`0x05`).
- Advance address by 64 bytes.
### Step 8: Memory-Mapped Verification & Readback
Read back the written memory region directly using BROM 32-bit read command `0xD1`:
1. Issue `0xD1` command for 1024-byte blocks (`256` 32-bit words):
- Send `b'\xD1' + struct.pack('>II', curr_addr, 256)`
- Receive echo header + 1028 bytes response.
2. Skip 2-byte header and 2-byte status footer.
3. Convert little-endian words to big-endian binary stream.
4. Perform byte-for-byte MD5 comparison against reference binary image.
### Step 9: Software Reset
1. Issue system reset command via RGU register:
- `write_reg16(0xA003001C, 0x1209)`
2. Device reboots cleanly into updated firmware.
---
## 4. Flash Layout Reference (Maxcom MM817 4MB SPI NOR)
```text
0x00000000 +-----------------------------------+
| ARM Bootloader (ARM_BL) | 10,240 bytes (0x2800)
0x00002800 +-----------------------------------+
| Extended Bootloader (EXT_BL) | 3,072 bytes (0x0C00)
0x00003400 +-----------------------------------+
| Boot Padding / Header | 3,072 bytes (0x0C00)
0x00004000 +-----------------------------------+
| Boot Region 2 Backup | 16,384 bytes (0x4000)
0x00008000 +-----------------------------------+
| Boot Region 3 Backup | 16,384 bytes (0x4000)
0x0000C000 +-----------------------------------+
| Main Firmware & File System | ~3.93 MB
0x00400000 +-----------------------------------+
```
---
## 5. Verification Checklist
| Test Phase | Expected Result | Verified Status |
| :--- | :--- | :---: |
| **BootROM Handshake** | Sync ACK `b'\xF5\xAF\xFA'`, Chip ID `0x6261` | PASS |
| **Watchdog Disable** | Reg `0xA0030000` = `0x2200` | PASS |
| **SPI Flash JEDEC ID** | Read `0x9F` returns manufacturer & device ID | PASS |
| **Sector Erase (4KB)** | Memory reads as `0xFF` across sector | PASS |
| **64-Byte Page Program** | Memory reads match programmed payload | PASS |
| **Full 16KB Verification**| 100% exact MD5 match against reference image | PASS |