initial upload
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
# 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 |
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user