From cad5bd6501868f9532d5b4a227ca156f9c9d1d8e Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Thu, 16 Sep 2021 11:09:30 +0200 Subject: Added NRF52 support. --- usb/usb_nrf.h | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 usb/usb_nrf.h (limited to 'usb/usb_nrf.h') 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 + +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 -- cgit v1.2.3