set rtl8710_flasher_command_read_id 0 set rtl8710_flasher_command_mass_erase 1 set rtl8710_flasher_command_sector_erase 2 set rtl8710_flasher_command_read 3 set rtl8710_flasher_command_write 4 set rtl8710_flasher_command_verify 5 set rtl8710_flasher_mac_address_offset 0xA088 set rtl8710_flasher_ready 0 set rtl8710_flasher_capacity 0 set rtl8710_flasher_auto_erase 0 set rtl8710_flasher_auto_verify 0 set rtl8710_flasher_auto_erase_sector 0 proc rtl8710_flasher_init {} { global rtl8710_flasher_ready rtl8710_flasher_firmware_ptr global rtl8710_flasher_buffer rtl8710_flasher_capacity global rtl8710_flasher_code if {!$rtl8710_flasher_ready} { set buf_ctrl [expr {$rtl8710_flasher_buffer + 0x00}] set buf_status [expr {$rtl8710_flasher_buffer + 0x08}] set buf_id [expr {$rtl8710_flasher_buffer + 0x0C}] halt # init buffer control regs mww $buf_status 0 mww $buf_ctrl 1 # load and start flasher write_memory $rtl8710_flasher_firmware_ptr 32 $rtl8710_flasher_code reg faultmask 1 reg sp 0x1003ef00 reg pc $rtl8710_flasher_firmware_ptr resume rtl8710_flasher_wait set id [rtl8710_flasher_mrw $buf_id] set rtl8710_flasher_capacity [expr {1 << (($id >> 16) & 0xFF)}] set rtl8710_flasher_ready 1 } } proc rtl8710_flasher_mrw {reg} { read_memory $reg 32 1 } proc rtl8710_flasher_wait {} { global rtl8710_flasher_buffer set addr [expr {$rtl8710_flasher_buffer + 0x00}] while {[rtl8710_flasher_mrw $addr]} {} } proc rtl8710_flasher_load_block {local_filename offset length} { global rtl8710_flasher_buffer set buffer_addr [expr {$rtl8710_flasher_buffer + 0x20}] load_image $local_filename [expr {$buffer_addr - $offset}] bin $buffer_addr $length } proc rtl8710_flasher_block {command offset len} { global rtl8710_flasher_buffer global rtl8710_flasher_command_read rtl8710_flasher_command_write rtl8710_flasher_command_verify # select command type switch $command { "read" {set cmd_type $rtl8710_flasher_command_read} "write" {set cmd_type $rtl8710_flasher_command_write} "verify" {set cmd_type $rtl8710_flasher_command_verify} default {error "Unknown command type: $command"} } mww [expr {$rtl8710_flasher_buffer + 0x04}] $cmd_type mww [expr {$rtl8710_flasher_buffer + 0x08}] 0x00000000 mww [expr {$rtl8710_flasher_buffer + 0x10}] $offset mww [expr {$rtl8710_flasher_buffer + 0x14}] $len mww [expr {$rtl8710_flasher_buffer + 0x00}] 0x00000001 rtl8710_flasher_wait set status [rtl8710_flasher_mrw [expr {$rtl8710_flasher_buffer + 0x08}]] if {[expr {$status > 0}]} { if {$command eq "verify"} { set status [rtl8710_flasher_mrw [expr {$rtl8710_flasher_buffer + 0x0C}]] set status [expr {$status + $offset}] } error "$command error, offset $status" } } proc rtl8710_flasher_read_block {offset len} { rtl8710_flasher_block "read" $offset $len } proc rtl8710_flasher_write_block {offset len} { rtl8710_flasher_block "write" $offset $len } proc rtl8710_flasher_verify_block {offset len} { rtl8710_flasher_block "verify" $offset $len } proc rtl8710_flash_read_id {} { global rtl8710_flasher_buffer rtl8710_flasher_capacity global rtl8710_flasher_command_read_id rtl8710_flasher_init # send read ID command mww [expr {$rtl8710_flasher_buffer + 0x04}] $rtl8710_flasher_command_read_id mww [expr {$rtl8710_flasher_buffer + 0x08}] 0 mww [expr {$rtl8710_flasher_buffer + 0x00}] 1 rtl8710_flasher_wait set id [rtl8710_flasher_mrw [expr {$rtl8710_flasher_buffer + 0x0C}]] set manufacturer_id [format "0x%02X" [expr {$id & 0xFF}]] set memory_type [format "0x%02X" [expr {($id >> 8) & 0xFF}]] set memory_capacity [expr {2 ** (($id >> 16) & 0xFF)}] echo "manufacturer ID: $manufacturer_id, memory type: $memory_type, memory capacity: $memory_capacity bytes" } proc rtl8710_flash_erase {type {offset 0}} { global rtl8710_flasher_buffer global rtl8710_flasher_command_mass_erase rtl8710_flasher_command_sector_erase rtl8710_flasher_init if {$type eq "mass"} { set cmd $rtl8710_flasher_command_mass_erase } elseif {$type eq "sector"} { set cmd $rtl8710_flasher_command_sector_erase mww [expr {$rtl8710_flasher_buffer + 0x10}] $offset } else { error "Unknown erase type: $type" } mww [expr {$rtl8710_flasher_buffer + 0x04}] $cmd mww [expr {$rtl8710_flasher_buffer + 0x08}] 0 mww [expr {$rtl8710_flasher_buffer + 0x00}] 1 rtl8710_flasher_wait } proc rtl8710_flash_mass_erase {} { rtl8710_flash_erase "mass" } proc rtl8710_flash_sector_erase {offset} { rtl8710_flash_erase "sector" $offset } proc rtl8710_flash_read {local_filename loc size} { global rtl8710_flasher_buffer rtl8710_flasher_buffer_size rtl8710_flasher_init set tmp "/tmp/_rtl8710_flasher.bin" for {set offset 0} {$offset < $size} {set offset [expr {$offset + $rtl8710_flasher_buffer_size}]} { set len [expr {($size - $offset) < $rtl8710_flasher_buffer_size ? ($size - $offset) : $rtl8710_flasher_buffer_size}] set flash_offset [expr {$loc + $offset}] echo "read $flash_offset" rtl8710_flasher_read_block $flash_offset $len dump_image $tmp [expr {$rtl8710_flasher_buffer + 0x20}] $len exec dd conv=notrunc if=$tmp of=$local_filename bs=1 seek=$offset echo "read $len bytes" } file delete -force $tmp } proc rtl8710_flash_write {local_filename loc} { global rtl8710_flasher_buffer_size rtl8710_flasher_sector_size global rtl8710_flasher_auto_erase rtl8710_flasher_auto_verify global rtl8710_flasher_auto_erase_sector rtl8710_flasher_init set size [file size $local_filename] for {set offset 0} {$offset < $size} {set offset [expr {$offset + $rtl8710_flasher_buffer_size}]} { set len [expr {($size - $offset) < $rtl8710_flasher_buffer_size ? ($size - $offset) : $rtl8710_flasher_buffer_size}] set flash_offset [expr {$loc + $offset}] echo "write offset $flash_offset" rtl8710_flasher_load_block $local_filename $offset $len if {$rtl8710_flasher_auto_erase} { set start_sector [expr {$flash_offset / $rtl8710_flasher_sector_size}] set end_sector [expr {($flash_offset + $len - 1) / $rtl8710_flasher_sector_size}] # erase any new sectors we encounter for {set sector $start_sector} {$sector <= $end_sector} {incr sector} { set sector_addr [expr {$sector * $rtl8710_flasher_sector_size}] if {$sector_addr >= $rtl8710_flasher_auto_erase_sector} { rtl8710_flash_sector_erase $sector_addr set rtl8710_flasher_auto_erase_sector [expr {$sector_addr + $rtl8710_flasher_sector_size}] } } } rtl8710_flasher_write_block $flash_offset $len echo "wrote $len bytes" if {$rtl8710_flasher_auto_verify} { echo "verify offset $flash_offset" rtl8710_flasher_verify_block $flash_offset $len } } } proc rtl8710_flash_verify {local_filename loc} { global rtl8710_flasher_buffer_size rtl8710_flasher_init set size [file size $local_filename] for {set offset 0} {$offset < $size} {set offset [expr {$offset + $rtl8710_flasher_buffer_size}]} { set len [expr {$size - $offset}] if {[expr {$len > $rtl8710_flasher_buffer_size}]} { set len $rtl8710_flasher_buffer_size } set flash_offset [expr {$loc + $offset}] echo "read offset $flash_offset" rtl8710_flasher_load_block $local_filename $offset $len echo "verify offset $flash_offset" rtl8710_flasher_verify_block $flash_offset $len } } proc rtl8710_flash_read_mac {} { global rtl8710_flasher_mac_address_offset rtl8710_flasher_buffer rtl8710_flasher_init rtl8710_flasher_read_block $rtl8710_flasher_mac_address_offset 6 set mac [read_memory [expr {$rtl8710_flasher_buffer + 0x20}] 8 6] set mac_str [join [lmap byte $mac {format %02X $byte}] ":"] echo "MAC address: $mac_str" } proc rtl8710_flash_auto_erase {on} { global rtl8710_flasher_auto_erase set rtl8710_flasher_auto_erase [expr {$on != 0}] echo "auto erase [expr {$on ? "on" : "off"}]" } proc rtl8710_flash_auto_verify {on} { global rtl8710_flasher_auto_verify set rtl8710_flasher_auto_verify [expr {$on != 0}] echo "auto verify [expr {$on ? "on" : "off"}]" } proc rtl8710_reboot {} { mww 0xE000ED0C 0x05FA0007 }