diff options
author | Vegard Storheil Eriksen <zyp@jvnv.net> | 2021-09-16 11:09:30 +0200 |
---|---|---|
committer | Vegard Storheil Eriksen <zyp@jvnv.net> | 2021-09-16 11:09:30 +0200 |
commit | cad5bd6501868f9532d5b4a227ca156f9c9d1d8e (patch) | |
tree | 7dce7fe31ed3f85ade53d38fe68b76e540403e5e /usb | |
parent | 3c526f3d0b30e200462290651f7c6a5eb30710a2 (diff) |
Added NRF52 support.nrf52
Diffstat (limited to 'usb')
-rw-r--r-- | usb/usb.h | 5 | ||||
-rw-r--r-- | usb/usb_nrf.h | 187 | ||||
-rw-r--r-- | usb/usb_nrf_def.h | 97 |
3 files changed, 289 insertions, 0 deletions
@@ -22,6 +22,11 @@ static L0_USB_t USB(0x40005c00, 0x40006000); static L0_USB_t USB(0x40006800, 0x40006c00); +#elif defined(NRF52840) +#include "usb_nrf.h" + +static USB_NRF_t USBD(0x40027000); + #endif #endif diff --git a/usb/usb_nrf.h b/usb/usb_nrf.h new file mode 100644 index 0000000..16e40a1 --- /dev/null +++ b/usb/usb_nrf.h @@ -0,0 +1,187 @@ +#ifndef LAKS_USB_USB_NRF_H +#define LAKS_USB_USB_NRF_H + +#include "generic.h" +#include "usb_nrf_def.h" + +#include <string.h> + +class USB_NRF : public USB_generic { + private: + USB_NRF_t& usb; + + uint32_t ep_in_busy; + + uint8_t buf_in[8][64]; + uint8_t buf_out[8][64]; + + protected: + virtual void hw_set_address(uint8_t addr) { + usb_rblog.log("SetAddress: %d", addr); + + // Do nothing, handled in hardware. + } + + virtual void hw_conf_ep(uint8_t ep, EPType type, uint32_t size) { + usb_rblog.log("Configuring EP%02x: size=%d", ep, size); + + uint8_t in = ep & 0x80; + ep &= 0x7f; + + if(in || ep == 0) { + usb.reg_in[ep].PTR = (uint32_t)&buf_in[ep]; + usb.reg.EPINEN |= 1 << ep; + } + + if(!in) { + usb.reg_out[ep].PTR = (uint32_t)&buf_out[ep]; + + usb.reg.SIZE_EPOUT[ep] = 0; + usb.reg.EPOUTEN |= 1 << ep; + } + } + + virtual void hw_set_stall(uint8_t ep) { + if(ep == 0) { + usb.tasks.EP0STALL = 1; + } + } + + public: + USB_NRF(USB_NRF_t& usb_periph, desc_t dev, desc_t conf) : USB_generic(dev, conf), usb(usb_periph) {} + + void init() { + *(volatile uint32_t*)0x4006ec00 = 0x00009375; + *(volatile uint32_t*)0x4006ed14 = 0x00000003; + *(volatile uint32_t*)0x4006ec00 = 0x00009375; + + usb.reg.ENABLE = 1; + + while(!(usb.reg.EVENTCAUSE & (1 << 11))); + + usb.reg.EVENTCAUSE = 1 << 11; + + *(volatile uint32_t*)0x4006ec00 = 0x00009375; + *(volatile uint32_t*)0x4006ed14 = 0x00000000; + *(volatile uint32_t*)0x4006ec00 = 0x00009375; + + usb.reg.USBPULLUP = 1; + } + + void process() { + if(usb.events.USBRESET) { + usb.events.USBRESET = 0; + + usb_rblog.log("USB Reset"); + + handle_reset(); + return; + } + + if(usb.events.EP0SETUP) { + usb.events.EP0SETUP = 0; + + uint8_t setupbuf[8] = { + (uint8_t)usb.reg.BMREQUESTTYPE, + (uint8_t)usb.reg.BREQUEST, + (uint8_t)usb.reg.WVALUEL, + (uint8_t)usb.reg.WVALUEH, + (uint8_t)usb.reg.WINDEXL, + (uint8_t)usb.reg.WINDEXH, + (uint8_t)usb.reg.WLENGTHL, + (uint8_t)usb.reg.WLENGTHH, + }; + + handle_setup((uint32_t*)&setupbuf); + } + + if(usb.events.EP0DATADONE) { + // TODO: Support multi-packet data stages. + usb.events.EP0DATADONE = 0; + + usb_rblog.log("Control data IN done, ACKing status stage."); + + usb.tasks.EP0STATUS = 1; + } + + /* + for(uint32_t ep = 0; ep <= 7; ep++) { + if(usb.events.ENDEPIN[ep]) { + usb.events.ENDEPIN[ep] = 0; + + ep_in_busy &= ~(1 << ep); + } + } + */ + + if(usb.reg.EPDATASTATUS) { + for(uint32_t ep = 1; ep <= 7; ep++) { + if((usb.reg.EPDATASTATUS & ((1 << 16) << ep)) == 0) { + continue; + } + + usb_rblog.log("EPDATA, starting DMA on ep %d", ep); + + usb.reg.EPDATASTATUS = (1 << 16) << ep; + + usb.reg_out[ep].MAXCNT = usb.reg.SIZE_EPOUT[ep]; + usb.tasks.STARTEPOUT[ep] = 1; + } + } + + for(uint32_t ep = 0; ep <= 7; ep++) { + if(usb.events.ENDEPOUT[ep]) { + usb.events.ENDEPOUT[ep] = 0; + + handle_out(ep, usb.reg_out[ep].AMOUNT); + } + } + } + + virtual bool ep_ready(uint32_t ep) { + //if(usb.events.ENDEPIN[ep]) { + // usb.events.ENDEPIN[ep] = 0; + // ep_in_busy &= ~(1 << ep); + //} + + if(usb.reg.EPDATASTATUS & (1 << ep)) { + usb.reg.EPDATASTATUS = 1 << ep; + + ep_in_busy &= ~(1 << ep); + } + + return (ep_in_busy & (1 << ep)) == 0; + } + + virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) { + usb_rblog.log("Writing, ep=%d, len=%d", ep, len); + + if(ep == 0 && len == 0 && (usb.reg.BMREQUESTTYPE & 0x80) == 0) { + usb_rblog.log("EP0 status ACK"); + usb.tasks.EP0STATUS = 1; + return; + } + + memcpy(&buf_in[ep], bufp, len); + + usb.reg_in[ep].MAXCNT = len; + + usb.tasks.STARTEPIN[ep] = 1; + + ep_in_busy |= 1 << ep; + } + + virtual uint32_t read(uint32_t ep, uint32_t* bufp, uint32_t len) { + usb_rblog.log("Reading, ep=%d, len=%d", ep, len); + + if(len > usb.reg_out[ep].AMOUNT) { + len = usb.reg_out[ep].AMOUNT; + } + + memcpy(bufp, &buf_out[ep], len); + + return len; + } +}; + +#endif diff --git a/usb/usb_nrf_def.h b/usb/usb_nrf_def.h new file mode 100644 index 0000000..0d56807 --- /dev/null +++ b/usb/usb_nrf_def.h @@ -0,0 +1,97 @@ +#ifndef LAKS_USB_USB_NRF_DEF_H +#define LAKS_USB_USB_NRF_DEF_H + +#include <stdint.h> + +class USB_NRF_t { + private: + struct tasks_t { + uint32_t _reserved; + volatile uint32_t STARTEPIN[8]; + volatile uint32_t STARTISOIN; + volatile uint32_t STARTEPOUT[8]; + volatile uint32_t STARTISOOUT; + volatile uint32_t EP0RCVOUT; + volatile uint32_t EP0STATUS; + volatile uint32_t EP0STALL; + volatile uint32_t DPDMDRIVE; + volatile uint32_t DPDMNODRIVE; + }; + + struct events_t { + volatile uint32_t USBRESET; + volatile uint32_t STARTED; + volatile uint32_t ENDEPIN[8]; + volatile uint32_t EP0DATADONE; + volatile uint32_t ENDISOIN; + volatile uint32_t ENDEPOUT[8]; + volatile uint32_t ENDISOOUT; + volatile uint32_t SOF; + volatile uint32_t USBEVENT; + volatile uint32_t EP0SETUP; + volatile uint32_t EPDATA; + }; + + struct reg_t { + volatile uint32_t SHORTS; + uint32_t _reserved[63]; + volatile uint32_t INTEN; + volatile uint32_t INTENSET; + volatile uint32_t INTENCLR; + uint32_t _reserved_1[61]; + volatile uint32_t EVENTCAUSE; + uint32_t _reserved_2[7]; + volatile uint32_t HALTED_EPIN[9]; + volatile uint32_t HALTED_EPOUT[9]; + volatile uint32_t EPSTATUS; + volatile uint32_t EPDATASTATUS; + volatile uint32_t USBADDR; + uint32_t _reserved_3[3]; + volatile uint32_t BMREQUESTTYPE; + volatile uint32_t BREQUEST; + volatile uint32_t WVALUEL; + volatile uint32_t WVALUEH; + volatile uint32_t WINDEXL; + volatile uint32_t WINDEXH; + volatile uint32_t WLENGTHL; + volatile uint32_t WLENGTHH; + volatile uint32_t SIZE_EPOUT[8]; + volatile uint32_t SIZE_ISOOUT; + uint32_t _reserved_4[15]; + volatile uint32_t ENABLE; + volatile uint32_t USBPULLUP; + volatile uint32_t DPDMVALUE; + volatile uint32_t DTOGGLE; + volatile uint32_t EPINEN; + volatile uint32_t EPOUTEN; + volatile uint32_t EPSTALL; + volatile uint32_t ISOSPLIT; + volatile uint32_t FRAMECNTR; + uint32_t _reserved_5[2]; + volatile uint32_t LOWPOWER; + volatile uint32_t ISOINCONFIG; + }; + + struct ep_reg_t { + volatile uint32_t PTR; + volatile uint32_t MAXCNT; + volatile uint32_t AMOUNT; + uint32_t _reserved[2]; + }; + + public: + tasks_t& tasks; + events_t& events; + reg_t& reg; + ep_reg_t* reg_in; + ep_reg_t* reg_out; + + USB_NRF_t(uint32_t reg_addr) : + tasks(*(tasks_t*)(reg_addr + 0x0)), + events(*(events_t*)(reg_addr + 0x100)), + reg(*(reg_t*)(reg_addr + 0x200)), + reg_in((ep_reg_t*)(reg_addr + 0x600)), + reg_out((ep_reg_t*)(reg_addr + 0x700)) {} +}; + +#endif |