Merge pull request #1254 from chmousset/add_efinix_usb_loader
[enh] added efinix atmel programmer
This commit is contained in:
commit
ba6d9f0751
|
@ -7,6 +7,9 @@
|
|||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from time import sleep
|
||||
import usb.core
|
||||
import usb.util
|
||||
|
||||
from litex.build.generic_programmer import GenericProgrammer
|
||||
|
||||
|
@ -35,3 +38,121 @@ class EfinixProgrammer(GenericProgrammer):
|
|||
msg += f"- access permissions.\n"
|
||||
msg += f"- hardware and cable."
|
||||
raise OSError(msg)
|
||||
|
||||
|
||||
class EfinixAtmelProgrammer:
|
||||
"""Reimplementation of Efinix's 'atmel_program.py' used on the Triton T8F81 dev board."""
|
||||
"""The original programmer only supports a single hexlified bitstream format, this one also"""
|
||||
"""supports binaries programming"""
|
||||
|
||||
vid = 0x03EB
|
||||
pid = 0x2013
|
||||
flash_erase_time = 7 # set to 20 in 'atmel_program.py' but W25Q80DV erases in 6s
|
||||
padding = 0xFF
|
||||
|
||||
def __init__(self):
|
||||
dev = usb.core.find(find_all=False, idVendor=self.vid, idProduct=self.pid)
|
||||
if not dev:
|
||||
raise ValueError(f"did not find Atmel USB programmer device with VID{self.vid:04x} PID{self.pid:04x}")
|
||||
dev.reset()
|
||||
reattach = False
|
||||
if os.name != 'nt':
|
||||
if dev.is_kernel_driver_active(0):
|
||||
reattach = True
|
||||
dev.detach_kernel_driver(0)
|
||||
dev.set_configuration()
|
||||
self.out_ep = dev[0][(0,0)][1]
|
||||
|
||||
# Data payload
|
||||
self.payload = []
|
||||
|
||||
def _expand_to_offset(self, offset):
|
||||
length = len(self.payload)
|
||||
if length < offset:
|
||||
self.payload += [self.padding] * (offset - length)
|
||||
elif length != 0:
|
||||
print(f"WARNING: potential overwrite of payload len={length} offset={offset}")
|
||||
|
||||
def _usb_w(self, data):
|
||||
assert len(data) <= 64
|
||||
self.out_ep.write(data)
|
||||
|
||||
def _prep_flash(self):
|
||||
self._usb_w([0x08]) # 'SPI Master'
|
||||
sleep(0.05)
|
||||
self._usb_w([0x09]) # 'flash_ready'
|
||||
sleep(0.05)
|
||||
|
||||
def _prep_load(self):
|
||||
self._usb_w([0x0B])
|
||||
sleep(0.001)
|
||||
self._usb_w([0x0C])
|
||||
sleep(0.002)
|
||||
self._usb_w([0x0D])
|
||||
sleep(0.01)
|
||||
self._usb_w([0x01] + [self.padding] * 10) # "write some initial junk bytes"
|
||||
|
||||
def _finish_load(self):
|
||||
self._usb_w([0x0E])
|
||||
|
||||
def _erase_flash(self):
|
||||
print("Erasing Flash...")
|
||||
self._usb_w([0x04])
|
||||
sleep(self.flash_erase_time)
|
||||
print("done")
|
||||
|
||||
def _reload(self):
|
||||
self._usb_w([0x06] + [self.padding] * 63) # toggle CRESET
|
||||
sleep(0.01)
|
||||
|
||||
def _send_packet(self, packet, flash=False):
|
||||
"""send 63 bytes of data"""
|
||||
assert len(packet) <= 63
|
||||
self._usb_w([0x03 if flash else 0x01] + packet)
|
||||
|
||||
def _send_payload(self, flash=False):
|
||||
print(f"Sending {len(self.payload)} bytes data")
|
||||
CHUNK = 63
|
||||
payload = self.payload
|
||||
while payload:
|
||||
# print(f"payload l={len(payload)}")
|
||||
length = min(CHUNK, len(payload))
|
||||
packet = [self.padding] * CHUNK
|
||||
packet = payload[0:length]
|
||||
packet[0:length] = payload[0:length]
|
||||
payload = payload[length:]
|
||||
self._send_packet(packet, flash)
|
||||
|
||||
self._usb_w([0x21] + [0xFF] * 63) # 'close connection'
|
||||
sleep(0.01)
|
||||
print("done")
|
||||
|
||||
def add_hex(self, offset, hexfile):
|
||||
"""Efinix has a simple 'one line per byte, HEX-encoded' bitstream file"""
|
||||
with open(hexfile, 'r') as f:
|
||||
hexfile = f.read()
|
||||
lines = hexfile.split('\n')
|
||||
while lines[-1] == '':
|
||||
lines = lines[:-1]
|
||||
payload = [int(l[0:2], 16) for l in lines]
|
||||
length = len(payload)
|
||||
self._expand_to_offset(offset)
|
||||
self.payload[offset:+length] = payload
|
||||
|
||||
def add_bin(self, offset, binfile):
|
||||
with open(binfile, 'rb') as f:
|
||||
payload = f.read()
|
||||
self._expand_to_offset(offset)
|
||||
self.payload[offset:+len(payload)] = payload
|
||||
|
||||
def load(self):
|
||||
self._prep_load()
|
||||
self._send_payload()
|
||||
self._finish_load()
|
||||
|
||||
def flash(self):
|
||||
self._prep_flash()
|
||||
self._erase_flash()
|
||||
self._prep_flash()
|
||||
self._send_payload(flash=True)
|
||||
self._reload()
|
||||
|
|
Loading…
Reference in New Issue