mpsse stuff
This commit is contained in:
parent
ca11c8e1e1
commit
c5a4a6b3e5
|
@ -88,6 +88,10 @@ void ftdi_init(void) {
|
|||
ftdi_eeprom[10] = 0x0000; // internal chip
|
||||
ftdi_eeprom[0x7f] = ftdi_eeprom_checksum_calc(ftdi_eeprom, 0x7f);
|
||||
|
||||
memset(ftdi_ifa, 0, sizeof ftdi_ifa);
|
||||
memset(ftdi_ifb, 0, sizeof ftdi_ifb);
|
||||
ftdi_ifa.lineprop = sio_bits_8 | sio_stop_1; // 8n1
|
||||
ftdi_ifb.lineprop = sio_bits_8 | sio_stop_1; // 8n1
|
||||
ftdi_ifa.index = 0;
|
||||
ftdi_ifb.index = 1;
|
||||
ftdi_if_init(&ftdi_ifa);
|
||||
|
@ -97,6 +101,26 @@ void ftdi_deinit(void) {
|
|||
// TODO: ???
|
||||
}
|
||||
|
||||
static uint8_t vnd_read_byte(struct ftdi_inteface* itf, int itfnum) {
|
||||
while (itf->rxavail <= 0) {
|
||||
if (!tud_vendor_n_mounted(itfnum) || !tud_vendor_n_available(itfnum)) {
|
||||
thread_yield();
|
||||
continue;
|
||||
}
|
||||
|
||||
itf->rxpos = 0;
|
||||
itf->rxavail = tud_vendor_n_read(itfnum, itf->bufbuf, sizeof itf->bufbuf);
|
||||
|
||||
if (itf->rxavail == 0) thread_yield();
|
||||
}
|
||||
|
||||
uint8_t rv = itf->bufbuf[itf->rxpos];
|
||||
++itf->rxpos;
|
||||
--itf->rxavail;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
typedef void (*ftfifo_write_fn)(struct ftdi_interface*, const uint8_t*, size_t);
|
||||
typedef size_t (*ftfifo_read_fn)(struct ftdi_interface*, uint8_t*, size_t);
|
||||
struct ftfifo_fns {
|
||||
|
@ -221,10 +245,24 @@ bool ftdi_control_xfer_cb(uint8_t rhport, uint8_t stage,
|
|||
|
||||
switch (req->bRequest) {
|
||||
case sio_cmd:
|
||||
if (req->wValue == sio_reset) ftdi_if_sio_reset(itf);
|
||||
else if (req->wValue == sio_tciflush) ftdi_if_sio_tciflush(itf);
|
||||
else if (req->wValue == sio_tcoflush) ftdi_if_sio_tcoflush(itf);
|
||||
else return false; // unk
|
||||
if (req->wValue == sio_reset) {
|
||||
itf->modem_mask = 0;
|
||||
itf->modem_data = 0;
|
||||
itf->flow = ftflow_none;
|
||||
itf->lineprop = sio_bits_8 | sio_stop_1; // 8n1
|
||||
itf->charen = 0;
|
||||
itf->bb_dir = 0;
|
||||
itf->bb_mode = sio_mode_reset;
|
||||
itf->mcu_addr_latch = 0;
|
||||
itf->rxavail = 0; itf->rxpos = 0;
|
||||
ftdi_if_sio_reset(itf);
|
||||
} else if (req->wValue == sio_tciflush) {
|
||||
itf->rxavail = 0; itf->rxpos = 0;
|
||||
ftdi_if_sio_tciflush(itf);
|
||||
} else if (req->wValue == sio_tcoflush) {
|
||||
// nothing extra to clear here I think
|
||||
ftdi_if_sio_tcoflush(itf);
|
||||
} else return false; // unk
|
||||
return tud_control_status(rhport, req);
|
||||
case sio_setmodemctrl:
|
||||
ftdi_if_set_modemctrl(itf,
|
||||
|
|
|
@ -143,6 +143,66 @@ enum ftdi_eep_defmode {
|
|||
fteep_mode_ft1284 = 8, // not impl. on 2232d, 232h-only
|
||||
};
|
||||
|
||||
// mpsse, mcuhost commands
|
||||
|
||||
// if bit 7 of an MPSSE command byte
|
||||
|
||||
enum ftdi_mpsse_cflg {
|
||||
ftmpsse_negedge_wr = 1<<0, // if 0, output bits on positive clock edige
|
||||
ftmpsse_bitmode = 1<<1, // if 0, byte mode
|
||||
ftmpsse_negedge_rd = 1<<2, // if 0, input bits on positive clock edge
|
||||
ftmpsse_lsbfirst = 1<<3, // if 0, msb first
|
||||
ftmpsse_tdiwrite = 1<<4, // 1 == do perform output
|
||||
ftmpsse_tdoread = 1<<5, // 1 == do perform input
|
||||
ftmpsse_tmswrite = 1<<6 // 1 == do perform output?
|
||||
};
|
||||
// bitmode: 1 length byte, max=7 (#bits = length+1) for separate bits
|
||||
// bytemode: 2 length bytes == number of bytes that follow
|
||||
// both tdiwrite and tdoread high: only one length value/equal number of bits in/out!
|
||||
// if both tdiwrite and tdoread are high, negedge_wr and negedge_rd must differ
|
||||
// tms read/writes: readback is from tdo, bit7 in databyte is tdi output, held constant
|
||||
// tdiwrite always 0, bitmode 1 in impls, can be ignored I guess
|
||||
// also always lsbfirst, but not too hard to support msbfirst too
|
||||
// idle levels (of eg. tms/cs) -> set_dirval?
|
||||
|
||||
enum ftdi_mpssemcu_cmd {
|
||||
ftmpsse_set_dirval_lo = 0x80, // sets initial clock level!
|
||||
ftmpsse_set_dirval_hi = 0x82,
|
||||
ftmpsse_read_lo = 0x81,
|
||||
ftmpsse_read_hi = 0x83,
|
||||
ftmpsse_loopback_on = 0x84,
|
||||
ftmpsse_loopback_off = 0x85,
|
||||
ftmpsse_set_clkdiv = 0x86, // period = 12MHz / ((1 + value16) * 2)
|
||||
|
||||
ftmpsse_flush = 0x87, // flush dev->host usb buffer
|
||||
ftmpsse_wait_io_hi = 0x88, // wait for gpiol1/io1 to be high
|
||||
ftmpsse_wait_io_lo = 0x89, // wait for gpiol1/io1 to be low
|
||||
|
||||
// technically ft2232h-only but we can support these, too
|
||||
ftmpsse_div5_disable = 0x8a, // ft2232h internally has a 5x faster clock, but slows it down by default
|
||||
ftmpsse_div5_enable = 0x8b, // for backwards compat. these two commands enable/disable that slowdown
|
||||
ftmpsse_data_3ph_en = 0x8c, // enable 3-phase data
|
||||
ftmpsse_data_3ph_dis = 0x8d, // disable 3-phase data
|
||||
ftmpsse_clockonly_bits = 0x8e, // enable clock for n bits, no data xfer
|
||||
ftmpsse_clockonly_bytes = 0x8f, // enable clock for n bytes, no data xfer
|
||||
ftmpsse_clock_wait_io_hi = 0x94, // wait_io_hi + clockonly
|
||||
ftmpsse_clock_wait_io_lo = 0x95, // wait_io_lo + clockonly
|
||||
ftmpsse_adapclk_enable = 0x96, // enable ARM JTAG adaptive clocking (rtck gpiol3 input)
|
||||
ftmpsse_adapclk_disable = 0x97, // disable ARM JTAG adaptive clocking (rtck gpiol3 input)
|
||||
ftmpsse_clock_bits_wait_io_hi = 0x9c, // clock_wait_io_hi + clockonly_bits
|
||||
ftmpsse_clock_bits_wait_io_lo = 0x9d, // clock_wait_io_lo + clockonly_bits
|
||||
ftmpsse_hi_is_tristate = 0x9e, // turns 1 output to tristate for selected outputs
|
||||
|
||||
ftmcu_flush = 0x87, // flush dev->host usb buffer
|
||||
ftmcu_wait_io_hi = 0x88, // wait for gpiol1/io1 to be high
|
||||
ftmcu_wait_io_lo = 0x89, // wait for gpiol1/io1 to be low
|
||||
|
||||
ftmcu_read8 = 0x90,
|
||||
ftmcu_read16 = 0x91,
|
||||
ftmcu_write8 = 0x92,
|
||||
ftmcu_write16 = 0x93
|
||||
};
|
||||
|
||||
// internal use only types
|
||||
|
||||
enum ftdi_mode { // combines EEPROM setting + bitmode
|
||||
|
@ -167,6 +227,7 @@ enum ftdi_flowctrl {
|
|||
};
|
||||
|
||||
struct ftdi_interface {
|
||||
// TODO soft fields maybe, because it's a mess with lots of padding right now
|
||||
int index;
|
||||
|
||||
uint8_t modem_mask;
|
||||
|
@ -174,7 +235,7 @@ struct ftdi_interface {
|
|||
|
||||
enum ftdi_flowctrl flow;
|
||||
|
||||
uint32_t baudrate; // TODO: what are the clock units of this? clock ticks of a 48MHz clock divided by 16?
|
||||
uint32_t baudrate;
|
||||
enum ftdi_sio_lineprop lineprop;
|
||||
|
||||
enum ftdi_sio_modemstat modemstat;
|
||||
|
@ -187,10 +248,14 @@ struct ftdi_interface {
|
|||
uint8_t bb_dir; // high/1 bit = output, 0=input
|
||||
enum ftdi_sio_bitmode bb_mode;
|
||||
|
||||
uint16_t mcu_addr_latch;
|
||||
|
||||
// "write" means write to hardware output pins
|
||||
// "read" means read from hardware input pins
|
||||
uint8_t writebuf[CFG_TUD_VENDOR_RX_BUFSIZE];
|
||||
uint8_t readbuf [CFG_TUD_VENDOR_TX_BUFSIZE];
|
||||
uint8_t bufbuf [CFG_TUD_VENDOR_RX_BUFSIZE]; // for buffered IO
|
||||
uint32_t rxavail, rxpos;
|
||||
};
|
||||
|
||||
extern struct ftdi_interface ftdi_ifa, ftdi_ifb;
|
||||
|
@ -241,7 +306,39 @@ size_t ftdi_if_asyncbb_read (struct ftdi_interface* itf, uint8_t* data, si
|
|||
void ftdi_if_syncbb_write (struct ftdi_interface* itf, const uint8_t* data, size_t datasize);
|
||||
size_t ftdi_if_syncbb_read (struct ftdi_interface* itf, uint8_t* data, size_t maxsize);
|
||||
|
||||
// TODO: mpsse, mcuhost
|
||||
|
||||
void ftdi_if_mpsse_flush(struct ftdi_interface* itf);
|
||||
void ftdi_if_mpsse_wait_io(struct ftdi_interface* itf, bool level);
|
||||
|
||||
void ftdi_if_mpsse_set_dirval_lo(struct ftdi_interface* itf, uint8_t dir, uint8_t val);
|
||||
void ftdi_if_mpsse_set_dirval_hi(struct ftdi_interface* itf, uint8_t dir, uint8_t val);
|
||||
uint8_t ftdi_if_mpsse_read_lo(struct ftdi_interface* itf);
|
||||
uint8_t ftdi_if_mpsse_read_hi(struct ftdi_interface* itf);
|
||||
void ftdi_if_mpsse_loopback_on(struct ftdi_interface* itf);
|
||||
void ftdi_if_mpsse_loopback_off(struct ftdi_interface* itf);
|
||||
void ftdi_if_mpsse_set_clkdiv(struct ftdi_interface* itf, uint16_t div);
|
||||
|
||||
uint8_t ftdi_if_mpsse_xfer_bits(struct ftdi_interface* itf, int flags, size_t nbits, uint8_t value);
|
||||
void ftdi_if_mpsse_xfer_bytes(struct ftdi_interface* itf, int flags, size_t nbytes, uint8_t* dst, const uint8_t* src);
|
||||
uint8_t ftdi_if_mpsse_tms_xfer(struct ftdi_interface* itf, int flags, size_t nbits, uint8_t value);
|
||||
|
||||
void ftdi_if_mpsse_div5(struct ftdi_interface* itf, bool enable);
|
||||
void ftdi_if_mpsse_data_3ph(struct ftdi_interface* itf, bool enable);
|
||||
void ftdi_if_mpsse_adaptive(struct ftdi_interface* itf, bool enable);
|
||||
|
||||
void ftdi_if_mpsse_clockonly(struct ftdi_interface* itf, uint32_t cycles);
|
||||
void ftdi_if_mpsse_clock_wait_io(struct ftdi_interface* itf, bool level);
|
||||
void ftdi_if_mpsse_clockonly_wait_io(struct ftdi_interface* itf, bool level, uint32_t cycles);
|
||||
void ftdi_if_mpsse_hi_is_tristate(struct ftdi_interface* itf, uint16_t pinmask);
|
||||
|
||||
|
||||
void ftdi_if_mcu_flush(struct ftdi_interface* itf);
|
||||
void ftdi_if_mcu_wait_io(struct ftdi_interface* itf, bool level);
|
||||
|
||||
uint8_t ftdi_if_mcu_read8 (struct ftdi_interface* itf, uint8_t addr);
|
||||
uint8_t ftdi_if_mcu_read16(struct ftdi_interface* itf, uint16_t addr);
|
||||
void ftdi_if_mcu_write8 (struct ftdi_interface* itf, uint8_t addr, uint8_t value);
|
||||
void ftdi_if_mcu_write16(struct ftdi_interface* itf, uint16_t addr, uint8_t value);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue