summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2023-12-12 00:11:41 +1100
committerDamien George <damien@micropython.org>2025-04-08 23:53:07 +1000
commit092d85557cc901a2840ac4abce3d12eb520c9765 (patch)
treeb2fb2debb64831ff04215a813187d07fde350ca8
parent1356860e2258cf2ecef43a65f40d83ddcbf98d0b (diff)
alif/tinyusb_port: Add Alif TinyUSB DCD driver.
From https://github.com/alifsemi/alif_vscode-tinyusb.git, commit c79f39361d334ee44f44fed30c56e70dbb368649 Signed-off-by: Damien George <damien.p.george@gmail.com> Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
-rw-r--r--ports/alif/tinyusb_port/alif_dcd_reg.h691
-rw-r--r--ports/alif/tinyusb_port/tusb_alif_dcd.c688
2 files changed, 1379 insertions, 0 deletions
diff --git a/ports/alif/tinyusb_port/alif_dcd_reg.h b/ports/alif/tinyusb_port/alif_dcd_reg.h
new file mode 100644
index 000000000..84220f6be
--- /dev/null
+++ b/ports/alif/tinyusb_port/alif_dcd_reg.h
@@ -0,0 +1,691 @@
+// *FORMAT-OFF*
+///-------------------------------------------------------------------------------------------------
+/// @file alif_dcd_reg.h
+/// @author karol.saja@alifsemi.com
+/// @version 0.0.1
+/// @date 2023-09-08
+/// @brief Low Level SPI driver
+///-------------------------------------------------------------------------------------------------
+
+#ifndef __ALIF_DCD_REG_H__
+#define __ALIF_DCD_REG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+//--------------------------------------------------------------------------------------------------
+
+#define _rw volatile uint32_t
+#define __w volatile uint32_t
+#define __r volatile const uint32_t
+
+volatile struct {
+ union {
+ _rw gsbuscfg0;
+ struct {
+ _rw incrbrstena : 1;
+ _rw incr4brstena : 1;
+ _rw incr8brstena : 1;
+ _rw incr16brstena : 1;
+ _rw incr32brstena : 1;
+ _rw incr64brstena : 1;
+ _rw incr128brstena : 1;
+ _rw incr256brstena : 1;
+ __r : 2;
+ _rw desbigend : 1;
+ _rw datbigend : 1;
+ __r : 4;
+ _rw deswrreqinfo : 4;
+ _rw datwrreqinfo : 4;
+ _rw desrdreqinfo : 4;
+ _rw datrdreqinfo : 4;
+ } gsbuscfg0_b;
+ };
+
+ union {
+ _rw gsbuscfg1;
+ struct {
+ __r : 8;
+ _rw pipetranslimit : 4;
+ _rw en1kpage : 1;
+ __r : 19;
+ } gsbuscfg1_b;
+ };
+
+ __r : 32; __r : 32;
+
+ union {
+ _rw gctl;
+ struct {
+ _rw dsblclkgtng : 1;
+ _rw gblhibernationen : 1;
+ __r : 1;
+ _rw disscramble : 1;
+ _rw scaledown : 2;
+ _rw ramclksel : 2;
+ __r : 2;
+ _rw sofitpsync : 1;
+ _rw coresoftreset : 1;
+ _rw prtcapdir : 2;
+ _rw frmscldwn : 2;
+ __r : 1;
+ _rw bypssetaddr : 1;
+ __r : 14;
+ } gctl_b;
+ };
+
+ __r : 32;
+
+ union {
+ _rw gsts;
+ struct {
+ __r curmod : 2;
+ __r : 2;
+ _rw buserraddrvld : 1;
+ _rw csrtimeout : 1;
+ __r device_ip : 1;
+ __r host_ip : 1;
+ __r adp_ip : 1;
+ __r bc_ip : 1;
+ __r otg_ip : 1;
+ __r ssic_ip : 1;
+ __r : 8;
+ __r cbelt : 12;
+ } gsts_b;
+ };
+
+ union {
+ _rw guctl1;
+ struct {
+ _rw loa_filter_en : 1;
+ _rw ovrld_l1_susp_com : 1;
+ _rw hc_parchk_disable : 1;
+ _rw hc_errata_enable : 1;
+ _rw l1_susp_thrld_for_host : 4;
+ _rw l1_susp_thrld_en_for_host : 1;
+ _rw dev_hs_nyet_bulk_spr : 1;
+ _rw resume_opmode_hs_host : 1;
+ __r : 1;
+ _rw disusb2refclkgtng : 1;
+ __r : 2;
+ _rw parkmode_disable_fsls : 1;
+ _rw parkmode_disable_hs : 1;
+ __r : 1;
+ _rw nak_per_enh_hs : 1;
+ _rw nak_per_enh_fs : 1;
+ _rw dev_lsp_tail_lock_dis : 1;
+ _rw ip_gap_add_on : 2;
+ _rw dev_l1_exit_by_hw : 1;
+ __r : 2;
+ _rw dev_trb_out_spr_ind : 1;
+ _rw tx_ipgap_linecheck_dis : 1;
+ _rw filter_se0_fsls_eop : 1;
+ __r : 1;
+ _rw dev_decouple_l1l2_evt : 1;
+ } guctl1_b;
+ };
+
+ union {
+ _rw gsnpsid;
+ };
+
+ __r : 32;
+
+ union {
+ _rw guid;
+ struct {
+ _rw userid : 32;
+ } guid_b;
+ };
+
+ union { // <- host only, leaving unimplemented for now [FIXME]
+ _rw guctl;
+ struct {
+ } guctl_b;
+ };
+
+ union {
+ _rw gbuserraddrlo;
+ struct {
+ _rw buserraddr : 32;
+ } gbuserraddrlo_b;
+ };
+
+ union {
+ _rw gbuserraddrhi;
+ struct {
+ _rw buserraddr : 32;
+ } gbuserraddrhi_b;
+ };
+
+ __r : 32; __r : 32;
+
+ __r ghwparams[8];
+
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32;
+
+ // base + 0x9C here
+
+ union {
+ _rw guctl2;
+ struct {
+ __r : 11;
+ _rw disablecfc : 1;
+ _rw enableepcacheevict : 1;
+ __r : 1;
+ _rw rst_actbitlater : 1;
+ __r : 4;
+ _rw en_hp_pm_timer : 7;
+ __r : 6;
+ } guctl2_b;
+ };
+
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+
+ // base + 0x100 here
+
+ union {
+ _rw gusb2phycfg0;
+ struct {
+ _rw toutcal : 3;
+ _rw phyif : 1;
+ __r ulpi_utmi_sel : 1;
+ __r fsintf : 1;
+ _rw suspendusb20 : 1;
+ _rw physel : 1;
+ _rw enblslpm : 1;
+ _rw xcvrdly : 1;
+ _rw usbtrdtim : 4;
+ __r : 5;
+ _rw lsipd : 3;
+ _rw lstrd : 3;
+ _rw ovrd_fsls_disc_time : 1;
+ __r inv_sel_hsic : 1;
+ __r hsic_con_width_adj : 2;
+ _rw ulpi_lpm_with_opmode_chk : 1;
+ _rw u2_freeclk_exists : 1;
+ _rw physoftrst : 1;
+ } gusb2phycfg0_b;
+ };
+
+ __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+
+ // base + 0x200 here
+
+ union {
+ _rw gtxfifosiz[4];
+ struct {
+ _rw txfdep : 16;
+ _rw txfstaddr : 16;
+ } gtxfifosiz_b[4];
+ };
+
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+
+ // base + 0x280 here
+
+ union {
+ _rw grxfifosiz[4];
+ struct {
+ _rw rxfdep : 16;
+ _rw rxfstaddr : 16;
+ } grxfifosiz_b[4];
+ };
+
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+
+ // base + 0x300 here
+
+ union {
+ _rw gevntadrlo0;
+ struct {
+ _rw evntadrlo : 32;
+ } gevntadrlo0_b;
+ };
+
+ union {
+ _rw gevntadrhi0;
+ struct {
+ _rw evntadrhi : 32;
+ } gevntadrhi0_b;
+ };
+
+ union {
+ _rw gevntsiz0;
+ struct {
+ _rw eventsiz : 16;
+ __r : 15;
+ _rw evntintrptmask : 1;
+ } gevntsiz0_b;
+ };
+
+ union {
+ _rw gevntcount0;
+ struct {
+ _rw evntcount : 16;
+ __r : 15;
+ _rw evnt_handler_busy : 1;
+ } gevntcount0_b;
+ };
+
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+
+ // base + 0x500 here
+
+ __r ghwparams8;
+
+ __r : 32; __r : 32; __r : 32;
+
+ // base + 0x510 here
+
+ union {
+ _rw gtxfifopridev;
+ struct {
+ _rw gtxfifopridev : 4;
+ __r : 28;
+ } gtxfifopridev_b;
+ };
+
+ __r : 32;
+
+ union {
+ _rw gtxfifoprihst;
+ struct {
+ _rw gtxfifoprihst : 2;
+ __r : 30;
+ } gtxfifoprihst_b;
+ };
+
+ union {
+ _rw grxfifoprihst;
+ struct {
+ _rw grxfifoprihst : 2;
+ __r : 30;
+ } grxfifoprihst_b;
+ };
+
+ __r : 32; __r : 32; __r : 32; __r : 32;
+
+ // base + 0x530 here
+
+ union {
+ _rw gfladj;
+ struct {
+ _rw gfladj_30mhz : 6;
+ __r : 1;
+ _rw gfladj_30mhz_sdbnd_sel : 1;
+ _rw gfladj_refclk_fladj : 14;
+ __r : 1;
+ _rw gfladj_refclk_lpm_sel : 1;
+ _rw gfladj_refclk_240mhz_decr : 7;
+ _rw gfladj_refclk_240mhzdecr_pls1 : 1;
+ } gfladj_b;
+ };
+
+ __r : 32; __r : 32; __r : 32;
+
+ // base + 0x540 here
+
+ union {
+ _rw gusb2rhbctl0;
+ struct {
+ _rw ovrd_l1timeout : 4;
+ __r : 28;
+ } gusb2rhbctl0_b;
+ };
+
+} *ugbl = (void *) (USB_BASE + 0xC100);
+
+volatile struct {
+ union {
+ _rw dcfg;
+ struct {
+ _rw devspd : 3;
+ _rw devaddr : 7;
+ __r : 2;
+ _rw intrnum : 5;
+ _rw nump : 5;
+ _rw lpmcap : 1;
+ _rw ignstrmpp : 1;
+ __r : 8;
+ } dcfg_b;
+ };
+
+ union {
+ _rw dctl;
+ struct {
+ __r : 1;
+ _rw tstctl : 4;
+ __w ulstchngreq : 4;
+ __r : 7;
+ _rw css : 1;
+ _rw crs : 1;
+ _rw l1hibernationen : 1;
+ _rw keepconnect : 1;
+ _rw lpm_nyet_thres : 4;
+ _rw hirdthres : 5;
+ __r : 1;
+ _rw csftrst : 1;
+ _rw run_stop : 1;
+ } dctl_b;
+ };
+
+ union {
+ _rw devten;
+ struct {
+ _rw dissconnevten : 1;
+ _rw usbrstevten : 1;
+ _rw connectdoneevten : 1;
+ _rw ulstcngen : 1;
+ _rw wkupevten : 1;
+ _rw hibernationreqevten : 1;
+ _rw u3l2l1suspen : 1;
+ _rw softevten : 1;
+ _rw l1suspen : 1;
+ _rw errticerrevten : 1;
+ __r : 2;
+ _rw vendevtstrcvden : 1;
+ __r : 1;
+ _rw l1wkupevten : 1;
+ __r : 1;
+ _rw eccerren : 1;
+ __r : 15;
+ } devten_b;
+ };
+
+ union {
+ _rw dsts;
+ struct {
+ __r connectspd : 3;
+ __r soffn : 14;
+ __r rxfifoempty : 1;
+ __r usblnkst : 4;
+ __r devctrlhlt : 1;
+ __r coreidle : 1;
+ __r sss : 1;
+ __r rss : 1;
+ __r : 2;
+ _rw sre : 1;
+ __r dcnrd : 1;
+ __r : 2;
+ } dsts_b;
+ };
+
+ union {
+ _rw dgcmdpar;
+ struct {
+ _rw parameter : 32;
+ } dgcmdpar_b;
+ };
+
+ union {
+ _rw dgcmd;
+ struct {
+ _rw cmdtyp : 8;
+ _rw cmdioc : 1;
+ __r : 1;
+ _rw cmdact : 1;
+ __r : 1;
+ __r cmdstatus : 4;
+ __r : 16;
+ } dgcmd_b;
+ };
+
+ __r : 32; __r : 32;
+
+ union {
+ _rw dalepena;
+ struct {
+ _rw usbactep : 32;
+ } dalepena_b;
+ };
+
+ __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+
+ // base + 0x100 here
+
+ struct {
+ union {
+ _rw par2;
+ struct {
+ _rw parameter : 32;
+ } par2_b;
+ };
+
+ union {
+ _rw par1;
+ struct {
+ _rw parameter : 32;
+ } par1_b;
+ };
+
+ union {
+ _rw par0;
+ struct {
+ _rw parameter : 32;
+ } par0_b;
+ };
+
+ union {
+ _rw depcmd;
+ struct {
+ _rw cmdtyp : 4;
+ __r : 4;
+ _rw cmdioc : 1;
+ __r : 1;
+ _rw cmdact : 1;
+ _rw hipri_forcerm : 1;
+ _rw cmdstatus : 4;
+ _rw commandparam : 16;
+ } depcmd_b;
+ };
+ } depcmd[8];
+
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+ __r : 32; __r : 32; __r : 32; __r : 32;
+
+ // base + 0x300 here
+
+ union {
+ _rw dev_imod0;
+ struct {
+ _rw device_imodi : 16;
+ _rw device_imocd : 16;
+ } dev_imod0_b;
+ };
+} *udev = (void *) (USB_BASE + 0xC700);
+
+//--------------------------------------------------------------------------------------------------
+
+typedef union {
+ _rw val : 32;
+ struct {
+ _rw sig : 8;
+ _rw evt : 5;
+ __r : 3;
+ _rw info : 9;
+ __r : 7;
+ } devt;
+ struct {
+ _rw sig : 1;
+ _rw ep : 5;
+ _rw evt : 4;
+ __r : 2;
+ _rw sts : 4;
+ _rw par : 16;
+ } depevt;
+} evt_t;
+
+//--------------------------------------------------------------------------------------------------
+
+enum {
+ CMDTYP_RESERVED = 0,
+ CMDTYP_DEPCFG,
+ CMDTYP_DEPXFERCFG,
+ CMDTYP_DEPGETSTATE,
+ CMDTYP_DEPSSTALL,
+ CMDTYP_DEPCSTALL,
+ CMDTYP_DEPSTRTXFER,
+ CMDTYP_DEPUPDXFER,
+ CMDTYP_DEPENDXFER,
+ CMDTYP_DEPSTARTCFG
+} DEPCMD_CMDTYP;
+
+enum {
+ DEVT_DISCONNEVT = 0,
+ DEVT_USBRST,
+ DEVT_CONNECTDONE,
+ DEVT_ULSTCHNG,
+ DEVT_WKUPEVT,
+ // DEVT_HIBRQ not implemented
+ DEVT_USBSUSP = 6,
+ DEVT_SOF,
+ DEVT_L1SUSP,
+ DEVT_ERRTICERR,
+ DEVT_CMDCMPLT,
+ DEVT_EVNTOVERFLOW,
+ DEVT_VNDDEVTSTRCVED,
+ // reserved
+ DEVT_L1RESM = 14,
+ // reserved
+ DEVT_ECCERR = 16
+} DEVT;
+
+enum {
+ // reserved
+ DEPEVT_XFERCOMPLETE = 1,
+ DEPEVT_XFERINPROGRESS,
+ DEPEVT_XFERNOTREADY,
+ // not implemented
+ DEPEVT_STREAMEVT = 6,
+ DEPEVT_EPCMDCMPLT
+} DEPEVT;
+
+enum {
+ // reserved
+ TRBCTL_NORMAL = 1,
+ TRBCTL_CTL_SETUP,
+ TRBCTL_CTL_STAT2,
+ TRBCTL_CTL_STAT3,
+ TRBCTL_CTL_DATA,
+ TRBCTL_ISO_FIRST,
+ TRBCTL_ISO,
+ TRBCTL_LINK,
+ TRBCTL_NORMAL_ZLP
+} TRBCTL;
+
+//--------------------------------------------------------------------------------------------------
+
+//--------------------------------------------------------------------------------------------------
+
+//--------------------------------------------------------------------------------------------------
+
+//--------------------------------------------------------------------------------------------------
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+
+#endif // __ALIF_DCD_REG_H__
diff --git a/ports/alif/tinyusb_port/tusb_alif_dcd.c b/ports/alif/tinyusb_port/tusb_alif_dcd.c
new file mode 100644
index 000000000..510f0e9c1
--- /dev/null
+++ b/ports/alif/tinyusb_port/tusb_alif_dcd.c
@@ -0,0 +1,688 @@
+// *FORMAT-OFF*
+/* Copyright (C) 2024 Alif Semiconductor - All Rights Reserved.
+ * Use, distribution and modification of this code is permitted under the
+ * terms stated in the Alif Semiconductor Software License Agreement
+ *
+ * You should have received a copy of the Alif Semiconductor Software
+ * License Agreement with this file. If not, please write to:
+ * contact@alifsemi.com, or visit: https://alifsemi.com/license
+ *
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED
+
+#if defined(CORE_M55_HE)
+#include "M55_HE.h"
+#elif defined(CORE_M55_HP)
+#include "M55_HP.h"
+#else
+#error "Unsupported core!"
+#endif
+
+#include "device/dcd.h"
+
+#include "alif_dcd_reg.h"
+
+#include "clk.h"
+#include "power.h"
+
+// #define TUSB_ALIF_DEBUG
+// #define TUSB_ALIF_DEBUG_DEPTH (2048)
+
+#if defined(TUSB_ALIF_DEBUG)
+#if (1 < TUSB_ALIF_DEBUG_DEPTH)
+#define LOG(...) memset(logbuf[bi % TUSB_ALIF_DEBUG_DEPTH], ' ', 48);\
+ snprintf(logbuf[(bi++) % TUSB_ALIF_DEBUG_DEPTH], 48, __VA_ARGS__);
+char logbuf[TUSB_ALIF_DEBUG_DEPTH][48];
+int bi = 0;
+#else
+#define LOG(...) memset(logbuf, ' ', 48);\
+ snprintf(logbuf, 48, __VA_ARGS__)
+char logbuf[48];
+#endif
+#else
+#define LOG(...)
+#endif
+
+/// Structs and Buffers --------------------------------------------------------
+
+static uint32_t _evnt_buf[1024] CFG_TUSB_MEM_SECTION __attribute__((aligned(4096))); // [TODO] runtime alloc
+static volatile uint32_t* _evnt_tail;
+
+static uint8_t _ctrl_buf[64] CFG_TUSB_MEM_SECTION __attribute__((aligned(32))); // [TODO] runtime alloc
+static uint32_t _xfer_trb[8][4] CFG_TUSB_MEM_SECTION __attribute__((aligned(32))); // [TODO] runtime alloc
+static uint16_t _xfer_bytes[8];
+static bool _ctrl_long_data = false;
+static bool _xfer_cfgd = false;
+// static bool _addr_req = false;
+static uint32_t _sts_stage = 0;
+
+/// Private Functions ----------------------------------------------------------
+
+static uint8_t _dcd_cmd_wait(uint8_t ep, uint8_t typ, uint16_t param);
+static uint8_t _dcd_start_xfer(uint8_t ep, void* buf, uint32_t size, uint8_t type);
+
+static void _dcd_handle_depevt(uint8_t ep, uint8_t evt, uint8_t sts, uint16_t par);
+static void _dcd_handle_devt(uint8_t evt, uint16_t info);
+
+/// API Extension --------------------------------------------------------------
+
+void dcd_uninit(void);
+
+/// Device Setup ---------------------------------------------------------------
+
+// Initializes the USB peripheral for device mode and enables it.
+// This function should enable internal D+/D- pull-up for enumeration.
+void dcd_init(uint8_t rhport)
+{
+ // enable 20mhz clock
+ enable_cgu_clk20m();
+ // enable usb peripheral clock
+ enable_usb_periph_clk();
+ // power up usb phy
+ enable_usb_phy_power();
+ // disable usb phy isolation
+ disable_usb_phy_isolation();
+ // clear usb phy power-on-reset signal
+ CLKCTL_PER_MST->USB_CTRL2 &= ~(1 << 8);
+
+ // force stop/disconnect
+ udev->dctl_b.run_stop = 0;
+
+ // dctl set csftrst to 1 and wait for 0
+ udev->dctl_b.csftrst = 1;
+ while(0 != udev->dctl_b.csftrst);
+
+ sys_busy_loop_us(50000);
+ ugbl->gctl_b.coresoftreset = 1;
+ ugbl->gusb2phycfg0_b.physoftrst = 1;
+ sys_busy_loop_us(50000);
+ ugbl->gusb2phycfg0_b.physoftrst = 0;
+ sys_busy_loop_us(50000);
+ ugbl->gctl_b.coresoftreset = 0;
+ sys_busy_loop_us(50000);
+
+ ugbl->gsbuscfg0 = 0x00000009;
+ // ugbl->gusb2phycfg0 = 0x4000154F; // [TODO] document as bits
+ uint32_t reg = ugbl->gusb2phycfg0;
+ reg &= ~((1 << 3) | (1 << 4) | (0xF << 10)); // clear phyif, ulpi_utmi_sel and usbtrdtim
+ reg |= ((1 << 3) | (5 << 10));
+ ugbl->gusb2phycfg0 = reg;
+
+ // set device speed (USBHS only)
+ udev->dcfg_b.devspd = 0x0; // HS, this will need #if condition [TODO]
+
+ // allocate ring buffer for events
+ memset(_evnt_buf, 0, sizeof(_evnt_buf));
+ RTSS_CleanDCache_by_Addr(_evnt_buf, sizeof(_evnt_buf));
+ _evnt_tail = _evnt_buf;
+ ugbl->gevntadrlo0 = (uint32_t) LocalToGlobal(_evnt_buf);
+ ugbl->gevntsiz0_b.eventsiz = (uint32_t) sizeof(_evnt_buf);
+ ugbl->gevntcount0_b.evntcount = 0;
+
+ // write devten to enable usb reset, conn done, link state change...
+ udev->devten_b.dissconnevten = 1;
+ udev->devten_b.usbrstevten = 1;
+ udev->devten_b.connectdoneevten = 1;
+ udev->devten_b.ulstcngen = 1;
+
+ // begin endpoint setup
+ _dcd_cmd_wait(0, CMDTYP_DEPSTARTCFG, 0);
+
+ // configure CONTROL IN and OUT eps
+ udev->depcmd[0].par1 = (0 << 25) | (1 << 10) | (1 << 8);
+ udev->depcmd[0].par0 = (0 << 22) | (0 << 17) | (512 << 3) | (0 << 1);
+ _dcd_cmd_wait(0, CMDTYP_DEPCFG, 0);
+
+ udev->depcmd[1].par1 = (1 << 25) | (1 << 10) | (1 << 8);
+ udev->depcmd[1].par0 = (0 << 22) | (0 << 17) | (512 << 3) | (0 << 1);
+ _dcd_cmd_wait(1, CMDTYP_DEPCFG, 0);
+
+ // set initial xfer configuration for CONTROL eps
+ udev->depcmd[0].par0 = 1;
+ _dcd_cmd_wait(0, CMDTYP_DEPXFERCFG, 0);
+
+ udev->depcmd[1].par0 = 1;
+ _dcd_cmd_wait(1, CMDTYP_DEPXFERCFG, 0);
+
+ // enable pull-ups
+ dcd_connect(rhport);
+
+ // prepare trb for the first setup packet
+ memset(_ctrl_buf, 0, sizeof(_ctrl_buf));
+ _xfer_trb[0][0] = (uint32_t) LocalToGlobal(_ctrl_buf);
+ _xfer_trb[0][1] = 0;
+ _xfer_trb[0][2] = 8;
+ _xfer_trb[0][3] = (1 << 11) | (1 << 10) | (TRBCTL_CTL_SETUP << 4) | (1 << 1) | (1 << 0);
+ RTSS_CleanDCache_by_Addr(_xfer_trb[0], sizeof(_xfer_trb[0]));
+
+ // send trb to the usb dma
+ udev->depcmd[0].par1 = (uint32_t) LocalToGlobal(_xfer_trb[0]);
+ udev->depcmd[0].par0 = 0;
+ _dcd_cmd_wait(0, CMDTYP_DEPSTRTXFER, 0);
+
+ // enable ep event interrupts for CONTROL OUT and IN
+ udev->dalepena_b.usbactep = (1 << 1) | (1 << 0);
+
+ // enable interrupts in the NVIC
+#if !defined(TUSB_ALIF_NO_IRQ_CFG)
+ NVIC_ClearPendingIRQ(USB_IRQ_IRQn);
+ NVIC_SetPriority(USB_IRQ_IRQn, 5);
+#endif
+ dcd_int_enable(rhport);
+}
+
+
+// Processes all the hardware generated events e.g bus reset, new data packet
+// from host... It will be called by application in the MCU USB interrupt handler.
+void dcd_int_handler(uint8_t rhport)
+{
+ LOG("%010u IRQ enter, evntcount %u", DWT->CYCCNT, ugbl->gevntcount0_b.evntcount);
+
+ // process failures first
+ if (ugbl->gsts_b.device_ip) {
+ if (ugbl->gsts_b.csrtimeout || ugbl->gsts_b.buserraddrvld) {
+ // buserraddrvld is usually set when USB tries to write to protected
+ // memory region. Check linker script to ensure USB event buffer and
+ // TRBs reside in bulk memory or other NS-allowed region
+ __BKPT(0);
+ }
+ }
+
+ // cycle through event queue
+ // evaluate on every iteration to prevent unnecessary isr exit/reentry
+ while (0 < ugbl->gevntcount0_b.evntcount) {
+ RTSS_InvalidateDCache_by_Addr(_evnt_buf, sizeof(_evnt_buf));
+ volatile evt_t e = {.val = *_evnt_tail++};
+
+ LOG("%010u IRQ loop, evntcount %u evnt %08x", DWT->CYCCNT,
+ ugbl->gevntcount0_b.evntcount, e.val);
+
+ // wrap around
+ if (_evnt_tail >= (_evnt_buf + 1024)) _evnt_tail = _evnt_buf;
+
+ // dispatch the right handler for the event type
+ if (0 == e.depevt.sig) { // DEPEVT
+ _dcd_handle_depevt(e.depevt.ep, e.depevt.evt, e.depevt.sts, e.depevt.par);
+ } else if (1 == e.devt.sig) { // DEVT
+ _dcd_handle_devt(e.devt.evt, e.devt.info);
+ } else {
+ // bad event??
+ LOG("Unknown event %u", e.val);
+ __BKPT(0);
+ }
+
+ // consume one event
+ ugbl->gevntcount0 = 4;
+ }
+
+ LOG("%010u IRQ exit, evntcount %u", DWT->CYCCNT, ugbl->gevntcount0_b.evntcount);
+}
+
+
+// Enables the USB device interrupt.
+// May be used to prevent concurrency issues when mutating data structures
+// shared between main code and the interrupt handler.
+void dcd_int_enable (uint8_t rhport)
+{
+ NVIC_EnableIRQ(USB_IRQ_IRQn);
+
+ (void) rhport;
+}
+
+// Disables the USB device interrupt.
+// May be used to prevent concurrency issues when mutating data structures
+// shared between main code and the interrupt handler.
+void dcd_int_disable(uint8_t rhport)
+{
+ NVIC_DisableIRQ(USB_IRQ_IRQn);
+
+ (void) rhport;
+}
+
+// Receive Set Address request, mcu port must also include status IN response.
+// If your peripheral automatically changes address during enumeration you may
+// leave this empty and also no queue an event for the corresponding SETUP packet.
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ LOG("%010u >%s", DWT->CYCCNT, __func__);
+
+ udev->dcfg_b.devaddr = dev_addr;
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+// Called to remote wake up host when suspended (e.g hid keyboard)
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ LOG("%010u >%s", DWT->CYCCNT, __func__);
+}
+
+// Connect by enabling internal pull-up resistor on D+/D-
+void dcd_connect(uint8_t rhport)
+{
+ udev->dctl_b.run_stop = 1;
+
+ (void) rhport;
+}
+
+// Disconnect by disabling internal pull-up resistor on D+/D-
+void dcd_disconnect(uint8_t rhport)
+{
+ // [TODO] clear all xfers and eps first
+
+ udev->dctl_b.run_stop = 0;
+
+ (void) rhport;
+}
+
+// Enable/Disable Start-of-frame interrupt. Default is disabled
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ LOG("%010u >%s", DWT->CYCCNT, __func__);
+}
+
+
+/// Endpoint Management --------------------------------------------------------
+
+// Invoked when a control transfer's status stage is complete.
+// May help DCD to prepare for next control transfer, this API is optional.
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
+{
+ LOG("%010u >%s", DWT->CYCCNT, __func__);
+
+ _ctrl_long_data = false;
+ _dcd_start_xfer(TUSB_DIR_OUT, _ctrl_buf, 8, TRBCTL_CTL_SETUP);
+}
+
+// Opening an endpoint is done for all non-control endpoints once the host picks
+// a configuration that the device should use.
+// At this point, the endpoint should be enabled in the peripheral and
+// configured to match the endpoint descriptor.
+// Pay special attention to the direction of the endpoint you can get from the
+// helper methods above. It will likely change what registers you are setting.
+// Also make sure to enable endpoint specific interrupts.
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
+{
+ LOG("%010u >%s %u %s %u %u", DWT->CYCCNT, __func__, desc_ep->bEndpointAddress,
+ desc_ep->bmAttributes.xfer == TUSB_XFER_BULK ? "bulk" : "int",
+ desc_ep->wMaxPacketSize, desc_ep->bInterval);
+
+ if (TUSB_XFER_ISOCHRONOUS == desc_ep->bmAttributes.xfer)
+ return false;
+
+ uint8_t ep = (tu_edpt_number(desc_ep->bEndpointAddress) << 1) |
+ tu_edpt_dir(desc_ep->bEndpointAddress);
+
+ // [TODO] verify that the num doesn't exceed hw max
+
+ if (false == _xfer_cfgd) {
+ _dcd_cmd_wait(0, CMDTYP_DEPSTARTCFG, 2);
+ _xfer_cfgd = true;
+ }
+
+ uint8_t fifo_num = TUSB_DIR_IN == tu_edpt_dir(desc_ep->bEndpointAddress) ?
+ tu_edpt_number(desc_ep->bEndpointAddress) : 0;
+ uint8_t interval = 0 < desc_ep->bInterval ? (desc_ep->bInterval - 1) : 0;
+
+ udev->depcmd[ep].par1 = (ep << 25) | (interval << 16) |
+ (1 << 10) | (1 << 8);
+ udev->depcmd[ep].par0 = (0 << 30) | (0 << 22) | (fifo_num << 17) |
+ ((desc_ep->wMaxPacketSize & 0x7FF) << 3) |
+ (desc_ep->bmAttributes.xfer << 1);
+
+ _dcd_cmd_wait(ep, CMDTYP_DEPCFG, 0);
+ udev->depcmd[ep].par0 = 1;
+ _dcd_cmd_wait(ep, CMDTYP_DEPXFERCFG, 0);
+
+ udev->dalepena_b.usbactep |= (1 << ep);
+
+ return true;
+}
+
+// Close all non-control endpoints, cancel all pending transfers if any.
+// Invoked when switching from a non-zero Configuration by SET_CONFIGURE therefore
+// required for multiple configuration support.
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ LOG("%010u >%s", DWT->CYCCNT, __func__);
+}
+
+// Close an endpoint. his function is used for implementing alternate settings.
+// After calling this, the device should not respond to any packets directed
+// towards this endpoint. When called, this function must abort any transfers in
+// progress through this endpoint, before returning.
+// Implementation is optional. Must be called from the USB task.
+// Interrupts could be disabled or enabled during the call.
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK;
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to
+// notify the stack
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+ // DEPSTRTXFER command
+ LOG("%010u >%s %u %x %u", DWT->CYCCNT, __func__, ep_addr, (uint32_t) buffer, total_bytes);
+
+ uint8_t ep = (tu_edpt_number(ep_addr) << 1) | tu_edpt_dir(ep_addr);
+
+ switch (ep) {
+ case 0: { // CONTROL OUT
+ if (0 < total_bytes) {
+ // DATA OUT request
+ _xfer_bytes[0] = total_bytes;
+ _dcd_start_xfer(0, buffer, total_bytes, TRBCTL_CTL_STAT3);
+ } else {
+ // TinyUSB explicitly requests STATUS OUT fetch after DATA IN
+ if (2 == ++_sts_stage) {
+ _sts_stage = 0;
+ dcd_event_xfer_complete(TUD_OPT_RHPORT, tu_edpt_addr(0, TUSB_DIR_OUT),
+ 0, XFER_RESULT_SUCCESS, true);
+ }
+ }
+ } break;
+ case 1: { // CONTROL IN
+ _xfer_bytes[1] = total_bytes;
+
+ if (0 < total_bytes) {
+ RTSS_CleanDCache_by_Addr(buffer, total_bytes);
+ uint8_t type = _ctrl_long_data ? TRBCTL_NORMAL : TRBCTL_CTL_DATA;
+ if (64 == total_bytes) {
+ _ctrl_long_data = true;
+ }
+ _dcd_start_xfer(1, buffer, total_bytes, type);
+ } else {
+ // status events are handled directly from the ISR when USB
+ // controller triggers XferNotReady event for status stage
+
+ if (2 == ++_sts_stage) {
+ _sts_stage = 0;
+ dcd_event_xfer_complete(TUD_OPT_RHPORT, tu_edpt_addr(0, TUSB_DIR_IN),
+ 0, XFER_RESULT_SUCCESS, true);
+ }
+ // dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN),
+ // 0, XFER_RESULT_SUCCESS, false);
+ }
+ } break;
+ default: { // DATA EPs (BULK & INTERRUPT only)
+ _xfer_bytes[ep] = total_bytes;
+ if (TUSB_DIR_IN == tu_edpt_dir(ep_addr)) {
+ RTSS_CleanDCache_by_Addr(buffer, total_bytes);
+ } else {
+ total_bytes = 512; // temporary hack, controller requires max
+ // size requests on OUT endpoints [FIXME]
+ }
+ uint8_t ret = _dcd_start_xfer(ep, buffer, total_bytes,
+ total_bytes ? TRBCTL_NORMAL : TRBCTL_NORMAL_ZLP);
+ LOG("start xfer sts %u", ret);
+ }
+ }
+
+ return true;
+}
+
+// Submit a transfer using fifo, When complete dcd_event_xfer_complete() is invoked to notify the stack
+// This API is optional, may be useful for register-based for transferring data.
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) TU_ATTR_WEAK;
+
+// Stall endpoint, any queuing transfer should be removed from endpoint
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ // DEPSSTALL command
+ LOG(">%s", __func__);
+
+ uint8_t ep = (tu_edpt_number(ep_addr) << 1) | tu_edpt_dir(ep_addr);
+
+ _dcd_cmd_wait(ep, CMDTYP_DEPSSTALL, 0);
+
+ if (0 == tu_edpt_number(ep_addr)) {
+ _ctrl_long_data = false;
+ _dcd_start_xfer(TUSB_DIR_OUT, _ctrl_buf, 8, TRBCTL_CTL_SETUP);
+ }
+}
+
+// clear stall, data toggle is also reset to DATA0
+// This API never calls with control endpoints, since it is auto cleared when
+// receiving setup packet
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ // DEPCSTALL command
+ LOG(">%s", __func__);
+
+ uint8_t ep = (tu_edpt_number(ep_addr) << 1) | tu_edpt_dir(ep_addr);
+
+ _dcd_cmd_wait(ep, CMDTYP_DEPCSTALL, 0);
+}
+
+void dcd_uninit(void)
+{
+ CLKCTL_PER_MST->USB_CTRL2 |= 1 << 8; // set usb phy power-on-reset signal
+ enable_usb_phy_isolation(); // enable usb phy isolation
+ disable_usb_phy_power(); // power down usb phy
+ disable_usb_periph_clk(); // disable usb peripheral clock
+}
+
+void USB_IRQHandler(void)
+{
+ dcd_int_handler(TUD_OPT_RHPORT);
+}
+
+
+static uint8_t _dcd_cmd_wait(uint8_t ep, uint8_t typ, uint16_t param)
+{
+ // capture phy state and disable lpm and suspend
+ uint32_t phycfg = ugbl->gusb2phycfg0;
+ ugbl->gusb2phycfg0_b.enblslpm = 0;
+ ugbl->gusb2phycfg0_b.suspendusb20 = 0;
+
+ // set up command in depcmd register
+ udev->depcmd[ep].depcmd_b.cmdtyp = typ;
+ udev->depcmd[ep].depcmd_b.cmdioc = 0;
+ udev->depcmd[ep].depcmd_b.commandparam = param;
+
+ // dispatch command and wait for completion
+ udev->depcmd[ep].depcmd_b.cmdact = 1;
+ while(0 != udev->depcmd[ep].depcmd_b.cmdact);
+
+ // restore phy state
+ ugbl->gusb2phycfg0 = phycfg;
+
+ return udev->depcmd[ep].depcmd_b.cmdstatus;
+}
+
+
+static void _dcd_handle_depevt(uint8_t ep, uint8_t evt, uint8_t sts, uint16_t par)
+{
+ LOG("%010u DEPEVT ep%u evt%u sts%u par%u", DWT->CYCCNT, ep, evt, sts, par);
+
+ switch (evt) {
+ case DEPEVT_XFERCOMPLETE: {
+ LOG("Transfer complete");
+ RTSS_InvalidateDCache_by_Addr(_xfer_trb[ep], sizeof(_xfer_trb[0]));
+ if (0 == ep) {
+ uint8_t trbctl = (_xfer_trb[0][3] >> 4) & 0x3F;
+ LOG("ep0 xfer trb3 = %08x", _xfer_trb[0][3]);
+ if (TRBCTL_CTL_SETUP == trbctl) {
+ RTSS_InvalidateDCache_by_Addr(_ctrl_buf, sizeof(_ctrl_buf));
+ LOG("%02x %02x %02x %02x %02x %02x %02x %02x",
+ _ctrl_buf[0], _ctrl_buf[1], _ctrl_buf[2], _ctrl_buf[3],
+ _ctrl_buf[4], _ctrl_buf[5], _ctrl_buf[6], _ctrl_buf[7]);
+ dcd_event_setup_received(TUD_OPT_RHPORT, _ctrl_buf, true);
+ } else if (TRBCTL_CTL_STAT3 == trbctl) {
+ if (0 < _xfer_bytes[0]) {
+ RTSS_InvalidateDCache_by_Addr((void*) _xfer_trb[0][0], _xfer_bytes[0]);
+ dcd_event_xfer_complete(TUD_OPT_RHPORT, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _xfer_bytes[0] - (_xfer_trb[0][2] & 0xFFFFFF),
+ XFER_RESULT_SUCCESS, true);
+ } else {
+ if (2 == ++_sts_stage) {
+ _sts_stage = 0;
+ dcd_event_xfer_complete(TUD_OPT_RHPORT, tu_edpt_addr(0, TUSB_DIR_OUT),
+ 0, XFER_RESULT_SUCCESS, true);
+
+ // *(volatile uint32_t*) 0x4900C000 ^= 8; // [TEMP]
+ }
+ }
+ } else {
+ // invalid TRBCTL value
+ __BKPT(0);
+ }
+ } else if (1 == ep) {
+ uint8_t trbctl = (_xfer_trb[1][3] >> 4) & 0x3F;
+ LOG("ep1 xfer trb3 = %08x trb2 = %08x", _xfer_trb[1][3], _xfer_trb[1][2]);
+ if (TRBCTL_CTL_STAT2 != trbctl) { // STATUS IN notification is done at xfer request
+ dcd_event_xfer_complete(TUD_OPT_RHPORT, tu_edpt_addr(0, TUSB_DIR_IN),
+ _xfer_bytes[1] - (_xfer_trb[1][2] & 0xFFFFFF),
+ XFER_RESULT_SUCCESS, true);
+ } else {
+ if (2 == ++_sts_stage) {
+ _sts_stage = 0;
+ dcd_event_xfer_complete(TUD_OPT_RHPORT, tu_edpt_addr(0, TUSB_DIR_IN),
+ 0, XFER_RESULT_SUCCESS, true);
+
+ // *(volatile uint32_t*) 0x4900C000 ^= 8; // [TEMP]
+ }
+ }
+ } else {
+ // [TODO] check if ep is open
+ LOG("ep%u xfer trb3 = %08x trb2 = %08x", ep, _xfer_trb[ep][3], _xfer_trb[ep][2]);
+ if (TUSB_DIR_OUT == tu_edpt_dir(tu_edpt_addr(ep >> 1, ep & 1))) {
+ RTSS_InvalidateDCache_by_Addr((void*) _xfer_trb[ep][0],
+ 512 - _xfer_trb[ep][2]);
+ // _xfer_bytes[ep] - _xfer_trb[ep][2]);
+ dcd_event_xfer_complete(TUD_OPT_RHPORT, tu_edpt_addr(ep >> 1, ep & 1),
+ 512 - _xfer_trb[ep][2],
+ XFER_RESULT_SUCCESS, true);
+ } else
+ dcd_event_xfer_complete(TUD_OPT_RHPORT, tu_edpt_addr(ep >> 1, ep & 1),
+ _xfer_bytes[ep] - _xfer_trb[ep][2],
+ XFER_RESULT_SUCCESS, true);
+ }
+ } break;
+ case DEPEVT_XFERINPROGRESS: {
+ LOG("Transfer in progress");
+ } break;
+ case DEPEVT_XFERNOTREADY: {
+ LOG("Transfer not ready: %s", sts & 8 ? "no TRB" : "no XFER");
+
+ // XferNotReady NotActive for status stage
+ if ((1 == ep) && (0b0010 == (sts & 0b1011))) {
+ _dcd_start_xfer(1, NULL, 0, TRBCTL_CTL_STAT2);
+ break;
+ }
+
+ if ((0 == ep) && (0b0010 == (sts & 0b1011))) {
+ _xfer_bytes[0] = 0;
+ _dcd_start_xfer(0, _ctrl_buf, 64, TRBCTL_CTL_STAT3);
+ break;
+ }
+
+ if ((1 > ep) && (sts & (1 << 3))) {
+ if (_xfer_trb[ep][3] & (1 << 0)) { // transfer was configured
+ // dependxfer can only block when actbitlater is set
+ ugbl->guctl2_b.rst_actbitlater = 1;
+ _dcd_cmd_wait(ep, CMDTYP_DEPENDXFER, 0);
+ ugbl->guctl2_b.rst_actbitlater = 0;
+
+ // reset the trb byte count and clean the cache
+ RTSS_InvalidateDCache_by_Addr(_xfer_trb[ep], sizeof(_xfer_trb[0]));
+ _xfer_trb[ep][2] = _xfer_bytes[ep];
+ RTSS_CleanDCache_by_Addr(_xfer_trb[ep], sizeof(_xfer_trb[ep]));
+
+ // prepare ep command
+ udev->depcmd[ep].par1 = (uint32_t) LocalToGlobal(_xfer_trb[ep]);
+ udev->depcmd[ep].par0 = 0;
+
+ // issue the block command and pass the status
+ _dcd_cmd_wait(ep, CMDTYP_DEPSTRTXFER, 0);
+
+ *(volatile uint32_t*) 0x49007000 ^= 16; // [TEMP]
+ }
+ }
+ } break;
+ case DEPEVT_EPCMDCMPLT: {
+ // redundant, currently no commands are issued with IOC bit set
+ } break;
+ }
+}
+
+
+static void _dcd_handle_devt(uint8_t evt, uint16_t info)
+{
+ LOG("%010u DEVT evt%u info%u", DWT->CYCCNT, evt, info);
+ switch (evt) {
+ case DEVT_USBRST: {
+ _xfer_cfgd = false;
+
+ // [TODO] issue depcstall for any ep in stall mode
+ udev->dcfg_b.devaddr = 0;
+ LOG("USB reset");
+ dcd_event_bus_reset(TUD_OPT_RHPORT, TUSB_SPEED_HIGH, true); // [TODO] actual speed
+ } break;
+ case DEVT_CONNECTDONE: {
+ // read conn speed from dsts
+ // program ramclksel in gctl if needed
+ LOG("Connect done");
+
+ udev->depcmd[0].par1 = (0 << 25) | (1 << 10) | (1 << 8);
+ udev->depcmd[0].par0 = (2 << 30) | (0 << 22) | (0 << 17) | (64 << 3) | (0 << 1);
+ _dcd_cmd_wait(0, CMDTYP_DEPCFG, 0);
+
+ udev->depcmd[1].par1 = (1 << 25) | (1 << 10) | (1 << 8);
+ udev->depcmd[1].par0 = (2 << 30) | (0 << 22) | (0 << 17) | (64 << 3) | (0 << 1);
+ _dcd_cmd_wait(1, CMDTYP_DEPCFG, 0);
+ } break;
+ case DEVT_ULSTCHNG: {
+ LOG("Link status change");
+ switch (info) {
+ case 0x3: { // suspend (L2)
+ dcd_event_bus_signal(TUD_OPT_RHPORT, DCD_EVENT_SUSPEND, true);
+ } break;
+ case 0x4: { // disconnected
+ dcd_event_bus_signal(TUD_OPT_RHPORT, DCD_EVENT_UNPLUGGED, true);
+ } break;
+ case 0xF: { // resume
+ dcd_event_bus_signal(TUD_OPT_RHPORT, DCD_EVENT_RESUME, true);
+ } break;
+ default: {}
+ }
+ // 0x0: ON state
+ // 0x2: L1 state (sleep)
+ // 0x3: L2 state (suspend)
+ // 0x4: disconnected state
+ // 0x5: early suspend
+ // 0xE: reset
+ // 0xF: resume
+ } break;
+ case DEVT_ERRTICERR: {
+ __BKPT(0);
+ } break;
+ default: {
+ LOG("Unknown DEVT event");
+ }
+ }
+}
+
+
+static uint8_t _dcd_start_xfer(uint8_t ep, void* buf, uint32_t size, uint8_t type)
+{
+ dcd_int_disable(TUD_OPT_RHPORT); // prevent race conditions
+
+ // program the trb and clean the cache
+ _xfer_trb[ep][0] = buf ? (uint32_t) LocalToGlobal(buf) : 0;
+ _xfer_trb[ep][1] = 0;
+ _xfer_trb[ep][2] = size;
+ _xfer_trb[ep][3] = (1 << 11) | (1 << 10) | (type << 4) | (1 << 1) | (1 << 0);
+ RTSS_CleanDCache_by_Addr(_xfer_trb[ep], sizeof(_xfer_trb[ep]));
+
+ // prepare ep command
+ udev->depcmd[ep].par1 = (uint32_t) LocalToGlobal(_xfer_trb[ep]);
+ udev->depcmd[ep].par0 = 0;
+
+ dcd_int_enable(TUD_OPT_RHPORT);
+
+ // issue the block command and pass the status
+ return _dcd_cmd_wait(ep, CMDTYP_DEPSTRTXFER, 0);
+}
+
+#endif // CFG_TUD_ENABLED