Files
lk/platform/stm32f7xx/usbc.c
Travis Geiselbrecht f7d8e2300c [warnings] add -Wshadow which helps detect local variables that override globals
Nothing particularly bad showed up but cleaned up a bit of code.
2020-07-25 16:49:25 -07:00

298 lines
7.4 KiB
C

/*
* Copyright (c) 2015 Travis Geiselbrecht
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#include <lk/reg.h>
#include <lk/trace.h>
#include <lk/debug.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <lk/err.h>
#include <dev/usb.h>
#include <dev/usbc.h>
#include <arch/arm/cm.h>
#include <platform/stm32.h>
#define LOCAL_TRACE 0
#define NUM_EP 5
struct ep_status {
usbc_transfer_t *transfer;
};
static struct {
bool do_resched;
struct ep_status ep_in[NUM_EP];
struct ep_status ep_out[NUM_EP];
PCD_HandleTypeDef handle;
} usbc;
void stm32_usbc_early_init(void) {
__HAL_RCC_USB_OTG_FS_CLK_ENABLE();
}
void stm32_usbc_init(void) {
LTRACE_ENTRY;
/* Set LL Driver parameters */
usbc.handle.Instance = USB_OTG_FS;
usbc.handle.Init.dev_endpoints = 4;
usbc.handle.Init.use_dedicated_ep1 = 0;
usbc.handle.Init.ep0_mps = 0x40;
usbc.handle.Init.dma_enable = 0;
usbc.handle.Init.low_power_enable = 1;
usbc.handle.Init.phy_itface = PCD_PHY_EMBEDDED;
usbc.handle.Init.Sof_enable = 0;
usbc.handle.Init.speed = PCD_SPEED_FULL;
usbc.handle.Init.vbus_sensing_enable = 0;
usbc.handle.Init.lpm_enable = 0;
/* Link The driver to the stack */
//usbc.handle.pData = pdev;
//pdev->pData = &hpcd;
/* Initialize LL Driver */
HAL_PCD_Init(&usbc.handle);
HAL_PCDEx_SetRxFiFo(&usbc.handle, 0x80);
HAL_PCDEx_SetTxFiFo(&usbc.handle, 0, 0x40);
HAL_PCD_EP_Open(&usbc.handle, 0, 0x40, EP_TYPE_CTRL);
HAL_PCD_EP_Open(&usbc.handle, 0x80, 0x40, EP_TYPE_CTRL);
}
void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
LTRACEF("epnum %u\n", epnum);
if (usbc.ep_out[epnum].transfer) {
// completing a transfer
usbc_transfer_t *t = usbc.ep_out[epnum].transfer;
usbc.ep_out[epnum].transfer = NULL;
LTRACEF("completing transfer %p\n", t);
PCD_EPTypeDef *ep = &hpcd->OUT_ep[epnum];
t->bufpos = ep->xfer_count;
t->result = 0;
t->callback(epnum, t);
usbc.do_resched = true;
}
}
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
PCD_EPTypeDef *ep = &hpcd->IN_ep[epnum];
LTRACEF("epnum %u, xfer count %u len %u\n", epnum, ep->xfer_count, ep->xfer_len);
if (epnum == 0) {
if (ep->xfer_count >= ep->xfer_len) {
// in transfer done, ready for receive status
HAL_PCD_EP_Receive(&usbc.handle, 0, 0, 0);
} else {
PANIC_UNIMPLEMENTED;
}
} else {
// in transfer done
if (usbc.ep_in[epnum].transfer) {
// completing a transfer
usbc_transfer_t *t = usbc.ep_in[epnum].transfer;
usbc.ep_in[epnum].transfer = NULL;
LTRACEF("completing transfer %p\n", t);
t->bufpos = ep->xfer_count;
t->result = 0;
t->callback(epnum, t);
usbc.do_resched = true;
}
}
}
void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) {
//LTRACE_ENTRY;
union usb_callback_args args;
args.setup = (struct usb_setup *)hpcd->Setup;
usbc_callback(USB_CB_SETUP_MSG, &args);
usbc.do_resched = true;
}
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
LTRACE_ENTRY;
}
void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) {
LTRACE_ENTRY;
/* fail all the outstanding transactions */
for (uint i = 0; i < NUM_EP; i++) {
if (usbc.ep_in[i].transfer) {
usbc_transfer_t *t = usbc.ep_in[i].transfer;
usbc.ep_in[i].transfer = NULL;
t->result = ERR_CANCELLED;
t->callback(i, t);
}
if (usbc.ep_out[i].transfer) {
usbc_transfer_t *t = usbc.ep_out[i].transfer;
usbc.ep_out[i].transfer = NULL;
t->result = ERR_CANCELLED;
t->callback(i, t);
}
}
usbc_callback(USB_CB_RESET, NULL);
usbc.do_resched = true;
}
void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) {
LTRACE_ENTRY;
usbc_callback(USB_CB_SUSPEND, NULL);
usbc.do_resched = true;
}
void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) {
LTRACE_ENTRY;
usbc_callback(USB_CB_RESUME, NULL);
usbc.do_resched = true;
}
void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
LTRACEF("epnum %u\n", epnum);
}
void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
LTRACEF("epnum %u\n", epnum);
}
void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) {
LTRACE_ENTRY;
}
void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) {
LTRACE_ENTRY;
}
status_t usbc_set_active(bool active) {
LTRACEF("active %u\n", active);
if (active) {
HAL_PCD_Start(&usbc.handle);
} else {
HAL_PCD_Stop(&usbc.handle);
}
return NO_ERROR;
}
void usbc_set_address(uint8_t address) {
//LTRACEF("address %u\n", address);
HAL_PCD_SetAddress(&usbc.handle, address);
}
void usbc_ep0_ack(void) {
LTRACE;
HAL_PCD_EP_Transmit(&usbc.handle, 0, 0, 0);
}
void usbc_ep0_stall(void) {
LTRACE;
HAL_PCD_EP_SetStall(&usbc.handle, 0x80);
}
void usbc_ep0_send(const void *buf, size_t len, size_t maxlen) {
LTRACEF("buf %p, len %zu, maxlen %zu\n", buf, len, maxlen);
HAL_PCD_EP_Transmit(&usbc.handle, 0, (void *)buf, MIN(len, maxlen));
}
void usbc_ep0_recv(void *buf, size_t len, ep_callback cb) {
LTRACEF("buf %p, len %zu\n", buf, len);
HAL_PCD_EP_Receive(&usbc.handle, 0, (void *)buf, len);
}
status_t usbc_setup_endpoint(ep_t ep, ep_dir_t dir, uint width, ep_type_t type) {
LTRACEF("ep %u dir %u width %u\n", ep, dir, width);
DEBUG_ASSERT(ep <= NUM_EP);
HAL_StatusTypeDef ret = HAL_PCD_EP_Open(&usbc.handle, ep | ((dir == USB_IN) ? 0x80 : 0), width, type);
// XXX be a little smarter here
if (dir == USB_IN) {
HAL_PCDEx_SetTxFiFo(&usbc.handle, ep, width);
}
return (ret == HAL_OK) ? NO_ERROR : ERR_GENERIC;
}
bool usbc_is_highspeed(void) {
return false;
}
status_t usbc_queue_rx(ep_t ep, usbc_transfer_t *transfer) {
LTRACEF("ep %u, transfer %p (buf %p, buflen %zu)\n", ep, transfer, transfer->buf, transfer->buflen);
DEBUG_ASSERT(ep <= NUM_EP);
DEBUG_ASSERT(usbc.ep_out[ep].transfer == NULL);
usbc.ep_out[ep].transfer = transfer;
HAL_PCD_EP_Receive(&usbc.handle, ep, transfer->buf, transfer->buflen);
return NO_ERROR;
}
status_t usbc_queue_tx(ep_t ep, usbc_transfer_t *transfer) {
LTRACEF("ep %u, transfer %p (buf %p, buflen %zu)\n", ep, transfer, transfer->buf, transfer->buflen);
DEBUG_ASSERT(ep <= NUM_EP);
DEBUG_ASSERT(usbc.ep_in[ep].transfer == NULL);
usbc.ep_in[ep].transfer = transfer;
HAL_PCD_EP_Transmit(&usbc.handle, ep, transfer->buf, transfer->buflen);
return NO_ERROR;
}
status_t usbc_flush_ep(ep_t ep) {
// Make sure The endpoint is in range.
DEBUG_ASSERT((ep & 0x7F) <= NUM_EP);
// Flush the FIFOs for the endpoint.
if (HAL_PCD_EP_Flush(&usbc.handle, ep) != HAL_OK) {
return ERR_GENERIC;
}
// Clear any transfers that we may have been waiting on.
if (ep & 0x80) {
usbc.ep_in[ep & 0x7F].transfer = NULL;
} else {
usbc.ep_out[ep].transfer = NULL;
}
return NO_ERROR;
}
void stm32_OTG_FS_IRQ(void) {
arm_cm_irq_entry();
//LTRACE_ENTRY;
usbc.do_resched = false;
HAL_PCD_IRQHandler(&usbc.handle);
arm_cm_irq_exit(usbc.do_resched);
}