Skip to content

Commit

Permalink
fixup! fixup! fixup! fixup! fixup! stm32: Add dw USB OTG FS usbdev dr…
Browse files Browse the repository at this point in the history
…iver
  • Loading branch information
bergzand committed Oct 28, 2019
1 parent 89b982f commit 11ced48
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 94 deletions.
2 changes: 1 addition & 1 deletion cpu/stm32_common/include/usbdev_stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ typedef struct {
const stm32_fshs_usb_config_t *config; /**< USB peripheral config */
uint8_t buffer[STM32_USB_FS_BUF_SPACE]; /**< Buffer space for endpoints */
size_t occupied; /**< Buffer space occupied */
bool suspended; /**< Suspend status */
size_t fifo_pos; /**< FIFO space occupied */
usbdev_ep_t *in; /**< In endpoints */
usbdev_ep_t *out; /**< Out endpoints */
} stm32_fshs_usb_t;
Expand Down
203 changes: 110 additions & 93 deletions cpu/stm32_common/periph/usbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,26 +244,26 @@ static void _ep_deactivate(usbdev_ep_t *ep)
}
}

static void _ep_enable(usbdev_ep_t *ep)
static void _ep_activate(usbdev_ep_t *ep)
{
stm32_fshs_usb_t *usbdev = (stm32_fshs_usb_t *)ep->dev;
const stm32_fshs_usb_config_t *conf = usbdev->config;

if (ep->dir == USB_EP_DIR_IN) {
_ep_in_disable(ep);
_device_regs(conf)->DAINTMSK |= 1 << ep->num;
_in_regs(conf, ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_SNAK |
USB_OTG_DIEPCTL_USBAEP |
_type_to_reg(ep->type) |
ep->num <<
USB_OTG_DIEPCTL_TXFNUM_Pos;
uint32_t diepctl = USB_OTG_DIEPCTL_SNAK |
USB_OTG_DIEPCTL_USBAEP |
_type_to_reg(ep->type) |
ep->num << USB_OTG_DIEPCTL_TXFNUM_Pos;
if (ep->num == 0) {
_in_regs(conf, ep->num)->DIEPCTL |= _ep0_size(ep->len);
diepctl |= _ep0_size(ep->len);
}
else {
_in_regs(conf, ep->num)->DIEPCTL |= ep->len;
_in_regs(conf, ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM;
diepctl |= ep->len;
diepctl |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM;
}
_in_regs(conf, ep->num)->DIEPCTL |= diepctl;
}
else {
_ep_out_disable(ep);
Expand Down Expand Up @@ -311,6 +311,57 @@ static usbdev_ep_t *_get_ep(stm32_fshs_usb_t *usbdev, unsigned num,
return dir == USB_EP_DIR_IN ? &usbdev->in[num] : &usbdev->out[num];
}

#ifdef DEVELHELP
static size_t _total_fifo_size(const stm32_fshs_usb_config_t *conf)
{
if (conf->type == STM32_USB_OTG_FS) {
#ifdef STM32_USB_OTG_FS_ENABLED
return USB_OTG_FS_TOTAL_FIFO_SIZE;
#else
return 0;
#endif /* STM32_USB_OTG_FS_ENABLED */
}
else {
#ifdef STM32_USB_OTG_HS_ENABLED
return USB_OTG_HS_TOTAL_FIFO_SIZE;
#else
return 0;
#endif /* STM32_USB_OTG_HS_ENABLED */
}

}
#endif /* DEVELHELP */

static void _configure_tx_fifo(stm32_fshs_usb_t *usbdev, size_t num, size_t len)
{
/* TX Fifo size must be at least 16 words long and must be word aligned */
size_t wordlen = len < (16 * sizeof(uint32_t))
? 16
: (len + (sizeof(uint32_t) - 1))/sizeof(uint32_t);

/* Check max size */
assert(usbdev->fifo_pos + wordlen <=
_total_fifo_size(usbdev->config)/sizeof(uint32_t));

_global_regs(usbdev->config)->DIEPTXF[num - 1] =
(wordlen << USB_OTG_TX0FD_Pos) |
(usbdev->fifo_pos);
usbdev->fifo_pos += wordlen;
}

static void _configure_fifo(stm32_fshs_usb_t *usbdev)
{
/* TODO: cleanup, more dynamic, etc */
const stm32_fshs_usb_config_t *conf = usbdev->config;

_global_regs(conf)->GRXFSIZ =
(_global_regs(conf)->GRXFSIZ & ~USB_OTG_GRXFSIZ_RXFD) |
STM32_FS_OUT_FIFO_SIZE;
_global_regs(conf)->DIEPTXF0_HNPTXFSIZ = (16 << USB_OTG_TX0FD_Pos) |
STM32_FS_OUT_FIFO_SIZE;
usbdev->fifo_pos = (STM32_FS_OUT_FIFO_SIZE + 16);
}

static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type,
usb_ep_dir_t dir, size_t buf_len)
{
Expand Down Expand Up @@ -340,11 +391,14 @@ static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type,
if (ep) {
if (usbdev->occupied + buf_len < STM32_USB_FS_BUF_SPACE) {
ep->buf = usbdev->buffer + usbdev->occupied;
ep->len = buf_len;
usbdev->occupied += buf_len;
ep->dir = dir;
ep->type = type;
ep->dev = dev;
ep->len = buf_len;
usbdev->occupied += buf_len;
if (ep->dir == USB_EP_DIR_IN && ep->num != 0) {
_configure_tx_fifo(usbdev, ep->num, ep->len);
}
}
}
return ep;
Expand Down Expand Up @@ -375,6 +429,18 @@ static void _flush_rx_fifo(stm32_fshs_usb_t *usbdev)
while (_global_regs(conf)->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) {}
}

static void _reset_eps(stm32_fshs_usb_t *usbdev)
{
const stm32_fshs_usb_config_t *conf = usbdev->config;

/* Set the NAK for all endpoints */
for (size_t i = 0; i < _max_endpoints(conf); i++) {
_out_regs(conf, i)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
_in_regs(conf, i)->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
_in_regs(conf, i)->DIEPCTL |= (i) << USB_OTG_DIEPCTL_TXFNUM_Pos;
}
}

static void _reset_periph(stm32_fshs_usb_t *usbdev)
{
const stm32_fshs_usb_config_t *conf = usbdev->config;
Expand All @@ -396,32 +462,15 @@ static void _enable_gpio(const stm32_fshs_usb_config_t *conf)
gpio_init_af(conf->dm, conf->af);
}

static void _configure_fifo(stm32_fshs_usb_t *usbdev)
{
/* TODO: cleanup, more dynamic, etc */
const stm32_fshs_usb_config_t *conf = usbdev->config;

_global_regs(conf)->GRXFSIZ =
(_global_regs(conf)->GRXFSIZ & ~USB_OTG_GRXFSIZ_RXFD) |
STM32_FS_OUT_FIFO_SIZE;
_global_regs(conf)->DIEPTXF0_HNPTXFSIZ = (64 << USB_OTG_TX0FD_Pos) |
STM32_FS_OUT_FIFO_SIZE;
_global_regs(conf)->DIEPTXF[0] = (64 << USB_OTG_TX0FD_Pos) |
(STM32_FS_OUT_FIFO_SIZE + 64);
_global_regs(conf)->DIEPTXF[1] = (64 << USB_OTG_TX0FD_Pos) |
(STM32_FS_OUT_FIFO_SIZE + 128);
_global_regs(conf)->DIEPTXF[2] = (64 << USB_OTG_TX0FD_Pos) |
(STM32_FS_OUT_FIFO_SIZE + 192);
}

static void _set_mode_device(stm32_fshs_usb_t *usbdev)
{
const stm32_fshs_usb_config_t *conf = usbdev->config;

/* Force device mode */
_global_regs(conf)->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD;
/* Spinlock to prevent a context switch here */
xtimer_spin(xtimer_ticks_from_usec(50 * US_PER_MS));
/* Spinlock to prevent a context switch here, needs a delay of 25 ms when
* force switching mode */
xtimer_spin(xtimer_ticks_from_usec(25 * US_PER_MS));
}

static void _usbdev_init(usbdev_t *dev)
Expand All @@ -439,7 +488,7 @@ static void _usbdev_init(usbdev_t *dev)

_enable_gpio(conf);

/* TODO: implement ULPI mode */
/* TODO: implement ULPI mode when a board is available */
#ifdef STM32_USB_OTG_HS_ENABLED
if (conf->type == STM32_USB_OTG_HS) {
/* Disable the ULPI clock in low power mode, this is essential for the
Expand Down Expand Up @@ -496,12 +545,7 @@ static void _usbdev_init(usbdev_t *dev)
(_global_regs(conf)->GUSBCFG & ~USB_OTG_GUSBCFG_TRDT) |
(trdt << USB_OTG_GUSBCFG_TRDT_Pos);


/* Set the NAK for all endpoints */
for (size_t i = 0; i < _max_endpoints(conf); i++) {
_out_regs(conf, i)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
_in_regs(conf, i)->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
}
_reset_eps(usbdev);

/* Disable the global NAK for both directions */
_device_regs(conf)->DCTL |= USB_OTG_DCTL_CGONAK | USB_OTG_DCTL_CGINAK;
Expand Down Expand Up @@ -595,46 +639,44 @@ static int _usbdev_set(usbdev_t *dev, usbopt_t opt,

static void _usbdev_esr(usbdev_t *dev)
{

stm32_fshs_usb_t *usbdev = (stm32_fshs_usb_t *)dev;
const stm32_fshs_usb_config_t *conf = usbdev->config;

if (_global_regs(conf)->GINTSTS & USB_OTG_GINTSTS_ENUMDNE) {
uint32_t int_status = _global_regs(conf)->GINTSTS;
uint32_t event = 0;

if (int_status & USB_OTG_GINTSTS_ENUMDNE) {
event = USB_OTG_GINTSTS_ENUMDNE;
/* Reset condition done */
_global_regs(conf)->GINTSTS |= USB_OTG_GINTSTS_ENUMDNE;
DEBUG("Reset done\n");
usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_RESET);
}
else if (_global_regs(conf)->GINTSTS & USB_OTG_GINTSTS_USBRST) {
else if (int_status & USB_OTG_GINTSTS_USBRST) {
/* Start of reset condition */
_global_regs(conf)->GINTSTS |= USB_OTG_GINTSTS_USBRST;
event = USB_OTG_GINTSTS_USBRST;

/* Reset all the things! */
_set_address(usbdev, 0);
_flush_rx_fifo(usbdev);

/* TODO: function */
for (size_t i = 0; i < _max_endpoints(conf); i++) {
_out_regs(conf, i)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
_in_regs(conf, i)->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
_in_regs(conf, i)->DIEPCTL |= (i) << USB_OTG_DIEPCTL_TXFNUM_Pos;
}
_reset_eps(usbdev);
_flush_fifo(usbdev, 0x10);

DEBUG("Reset start\n");
}
else if (_global_regs(conf)->GINTSTS & USB_OTG_GINTSTS_SRQINT) {
else if (int_status & USB_OTG_GINTSTS_SRQINT) {
/* Reset done */
_global_regs(conf)->GINTSTS |= USB_OTG_GINTSTS_SRQINT;
event = USB_OTG_GINTSTS_SRQINT;
DEBUG("Session request\n");
}
else if (_global_regs(conf)->GINTSTS & USB_OTG_GINTSTS_USBSUSP) {
else if (int_status & USB_OTG_GINTSTS_USBSUSP) {
DEBUG("SUSPEND\n");
_global_regs(conf)->GINTSTS |= USB_OTG_GINTSTS_USBSUSP;
event = USB_OTG_GINTSTS_USBSUSP;
usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_SUSPEND);
/* Disable USB clock */
*_pcgcctl_reg(conf) |= USB_OTG_PCGCCTL_STOPCLK;
pm_unblock(STM32_PM_STOP);
}
else if (_global_regs(conf)->GINTSTS & USB_OTG_GINTSTS_WKUINT) {
else if (int_status & USB_OTG_GINTSTS_WKUINT) {
pm_block(STM32_PM_STOP);
DEBUG("WAKE\n");
/* reenable USB clock */
Expand All @@ -644,6 +686,7 @@ static void _usbdev_esr(usbdev_t *dev)
usbdev->usbdev.cb(&usbdev->usbdev, USBDEV_EVENT_RESUME);
}

_global_regs(conf)->GINTSTS |= event;
_global_regs(conf)->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
}

Expand Down Expand Up @@ -721,7 +764,7 @@ static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt,
case USBOPT_EP_ENABLE:
assert(value_len == sizeof(usbopt_enable_t));
if (*((usbopt_enable_t *)value)) {
_ep_enable(ep);
_ep_activate(ep);
}
else {
_ep_deactivate(ep);
Expand All @@ -739,7 +782,6 @@ static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt,
return res;
}


static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len)
{
stm32_fshs_usb_t *usbdev = (stm32_fshs_usb_t *)ep->dev;
Expand All @@ -765,8 +807,11 @@ static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len)
* When DMA is enabled, filling the transmit FIFO is handled by the DMA
* controller in the peripheral
*/

/* Packet count seems not to decrement below 1 and thus is broken in
* combination with the TXFE irq, it does however work with control
* transfers and when using DMA */
uint32_t dieptsiz = (len & USB_OTG_DIEPTSIZ_XFRSIZ_Msk);
/* Packet count seems to be broken in combination with the TXFE irq */
if (ep->num == 0 || conf->dma) {
dieptsiz |= (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos);
}
Expand All @@ -778,9 +823,8 @@ static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len)
_device_regs(conf)->DAINTMSK |= 1 << ep->num;
_device_regs(conf)->DIEPEMPMSK |= 1 << ep->num;

_in_regs(conf,
ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_CNAK |
USB_OTG_DIEPCTL_EPENA;
_in_regs(conf, ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_CNAK |
USB_OTG_DIEPCTL_EPENA;

if (len > 0
#ifdef STM32_USB_OTG_HS_ENABLED
Expand All @@ -795,24 +839,6 @@ static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len)
fifo[i] = ep_buf[i];
}
}
//if (ep->num != 0) {
// DEBUG("READY %u MSK %lx, CTL: %lx, Aint %lx, I: %lx, S %lx\n",
// ep->num,
// _device_regs(conf)->DIEPEMPMSK,
// _in_regs(conf, ep->num)->DIEPCTL,
// _device_regs(conf)->DAINTMSK,
// _in_regs(conf, ep->num)->DIEPINT,
// _in_regs(conf, ep->num)->DIEPTSIZ);
// while (!(_in_regs(conf, ep->num)->DIEPINT & USB_OTG_DIEPINT_TXFE)) {
// DEBUG("READY %u MSK %lx, CTL: %lx, Aint %lx, I: %lx, S %lx\n",
// ep->num,
// _device_regs(conf)->DIEPEMPMSK,
// _in_regs(conf, ep->num)->DIEPCTL,
// _device_regs(conf)->DAINTMSK,
// _in_regs(conf, ep->num)->DIEPINT,
// _in_regs(conf, ep->num)->DIEPTSIZ);
// }
//}
}
else {
/* Abort when the endpoint is not active, prevents hangs,
Expand All @@ -825,16 +851,12 @@ static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len)
_out_regs(conf, ep->num)->DOEPDMA = (uint32_t)ep->buf;
}
#endif /* STM32_USB_OTG_HS_ENABLED */

/* Configure to receive one packet with ep->len as max length */
_out_regs(conf,
ep->num)->DOEPTSIZ = (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) |
(ep->len &
USB_OTG_DOEPTSIZ_XFRSIZ_Msk);
/* TODO: test with CID_1x if essential, CID_2x doesn't care */
if (ep->num == 0) {
_out_regs(conf,
ep->num)->DOEPTSIZ |= 1 << USB_OTG_DOEPTSIZ_STUPCNT_Pos;
}
uint32_t doeptsiz = (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) |
(ep->len & USB_OTG_DOEPTSIZ_XFRSIZ_Msk);
doeptsiz |= (ep->num == 0) ? 1 << USB_OTG_DOEPTSIZ_STUPCNT_Pos : 0;
_out_regs(conf, ep->num)->DOEPTSIZ = doeptsiz;
_out_regs(conf, ep->num)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK |
USB_OTG_DOEPCTL_EPENA |
_type_to_reg(ep->type);
Expand Down Expand Up @@ -900,8 +922,6 @@ static void _usbdev_ep_esr(usbdev_ep_t *ep)

if (ep->dir == USB_EP_DIR_IN) {
uint32_t status = _in_regs(conf, ep->num)->DIEPINT;
if (ep->num != 0)
DEBUG("ESR %lx : %lx\n", status, _in_regs(conf, ep->num)->DIEPTSIZ);

/* XFRC interrupt is used for all endpoints when DMA is enabled */
#ifdef STM32_USB_OTG_HS_ENABLED
Expand All @@ -918,9 +938,6 @@ static void _usbdev_ep_esr(usbdev_ep_t *ep)
_device_regs(conf)->DIEPEMPMSK &= ~(1 << ep->num);
usbdev->usbdev.epcb(ep, USBDEV_EVENT_TR_COMPLETE);
}
else {
DEBUG("UNKNOWN\n");
}
}
else {
/* RX FIFO not empty and the endpoint matches the function argument */
Expand Down

0 comments on commit 11ced48

Please sign in to comment.