Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 22 additions & 121 deletions drivers/usb/udc/udc_dwc2.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,91 +69,6 @@ enum dwc2_drv_event_type {
/* Percentage limit of how much SPRAM can be allocated for RxFIFO */
#define MAX_RXFIFO_GDFIFO_PERCENTAGE 25

enum dwc2_suspend_type {
DWC2_SUSPEND_NO_POWER_SAVING,
DWC2_SUSPEND_HIBERNATION,
};

/* Registers that have to be stored before Partial Power Down or Hibernation */
struct dwc2_reg_backup {
uint32_t gotgctl;
uint32_t gahbcfg;
uint32_t gusbcfg;
uint32_t gintmsk;
uint32_t grxfsiz;
uint32_t gnptxfsiz;
uint32_t gi2cctl;
uint32_t glpmcfg;
uint32_t gdfifocfg;
union {
uint32_t dptxfsiz[15];
uint32_t dieptxf[15];
};
uint32_t dcfg;
uint32_t dctl;
uint32_t diepmsk;
uint32_t doepmsk;
uint32_t daintmsk;
uint32_t diepctl[16];
uint32_t dieptsiz[16];
uint32_t diepdma[16];
uint32_t doepctl[16];
uint32_t doeptsiz[16];
uint32_t doepdma[16];
uint32_t pcgcctl;
};

/* Driver private data per instance */
struct udc_dwc2_data {
struct k_spinlock lock;
struct k_thread thread_data;
/* Main events the driver thread waits for */
struct k_event drv_evt;
/* Endpoint is considered disabled when there is no active transfer */
struct k_event ep_disabled;
/* Transfer triggers (IN on bits 0-15, OUT on bits 16-31) */
atomic_t xfer_new;
/* Finished transactions (IN on bits 0-15, OUT on bits 16-31) */
atomic_t xfer_finished;
struct dwc2_reg_backup backup;
uint32_t ghwcfg1;
uint32_t max_xfersize;
uint32_t max_pktcnt;
uint32_t tx_len[16];
uint32_t rx_siz[16];
/* Isochronous endpoint enabled (IN on bits 0-15, OUT on bits 16-31) */
uint32_t iso_enabled;
uint16_t iso_in_rearm;
uint16_t iso_out_rearm;
uint16_t ep_out_disable;
uint16_t ep_out_stall;
uint16_t txf_set;
uint16_t pending_tx_flush;
uint16_t dfifodepth;
uint16_t rxfifo_depth;
uint16_t max_txfifo_depth[16];
uint16_t sof_num;
/* Configuration flags */
unsigned int dynfifosizing : 1;
unsigned int bufferdma : 1;
unsigned int syncrst : 1;
/* Defect workarounds */
unsigned int wa_essregrestored : 1;
/* Runtime state flags */
unsigned int hibernated : 1;
unsigned int enumdone : 1;
unsigned int enumspd : 2;
unsigned int ignore_ep0_nakeff : 1;
enum dwc2_suspend_type suspend_type;
/* Number of endpoints including control endpoint */
uint8_t numdeveps;
/* Number of IN endpoints including control endpoint */
uint8_t ineps;
/* Number of OUT endpoints including control endpoint */
uint8_t outeps;
uint8_t setup[8];
};

static void udc_dwc2_ep_disable(const struct device *dev,
struct udc_ep_config *const cfg,
bool stall, bool wait);
Expand Down Expand Up @@ -190,13 +105,6 @@ static int dwc2_init_pinctrl(const struct device *dev)
}
#endif

static inline struct usb_dwc2_reg *dwc2_get_base(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;

return config->base;
}

static void dwc2_wait_for_bit(const struct device *dev,
mem_addr_t addr, uint32_t bit)
{
Expand Down Expand Up @@ -543,7 +451,7 @@ static int dwc2_tx_fifo_write(const struct device *dev,
return -ENOTSUP;
}

sys_write32((uint32_t)buf->data,
sys_write32((uint32_t)POINTER_TO_UINT(buf->data),
(mem_addr_t)&base->in_ep[ep_idx].diepdma);
}

Expand Down Expand Up @@ -740,7 +648,7 @@ static void dwc2_prep_rx(const struct device *dev, struct net_buf *buf,
return;
}

sys_write32((uint32_t)data,
sys_write32((uint32_t)POINTER_TO_UINT(data),
(mem_addr_t)&base->out_ep[ep_idx].doepdma);
}

Expand Down Expand Up @@ -883,8 +791,7 @@ static int dwc2_handle_evt_din(const struct device *dev,

static void dwc2_backup_registers(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
struct udc_dwc2_data *const priv = udc_get_private(dev);
struct dwc2_reg_backup *backup = &priv->backup;

Expand Down Expand Up @@ -940,8 +847,7 @@ static void dwc2_backup_registers(const struct device *dev)
static void dwc2_restore_essential_registers(const struct device *dev,
bool rwup, bool bus_reset)
{
const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
struct udc_dwc2_data *const priv = udc_get_private(dev);
struct dwc2_reg_backup *backup = &priv->backup;
uint32_t pcgcctl = backup->pcgcctl & USB_DWC2_PCGCCTL_RESTOREVALUE_MASK;
Expand Down Expand Up @@ -995,8 +901,7 @@ static void dwc2_restore_essential_registers(const struct device *dev,

static void dwc2_restore_device_registers(const struct device *dev, bool rwup)
{
const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
struct udc_dwc2_data *const priv = udc_get_private(dev);
struct dwc2_reg_backup *backup = &priv->backup;

Expand Down Expand Up @@ -1039,8 +944,7 @@ static void dwc2_restore_device_registers(const struct device *dev, bool rwup)

static void dwc2_enter_hibernation(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
struct udc_dwc2_data *const priv = udc_get_private(dev);
mem_addr_t gpwrdn_reg = (mem_addr_t)&base->gpwrdn;
mem_addr_t pcgcctl_reg = (mem_addr_t)&base->pcgcctl;
Expand Down Expand Up @@ -1087,8 +991,7 @@ static void dwc2_enter_hibernation(const struct device *dev)
static void dwc2_exit_hibernation(const struct device *dev,
bool rwup, bool bus_reset)
{
const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
struct udc_dwc2_data *const priv = udc_get_private(dev);
mem_addr_t gpwrdn_reg = (mem_addr_t)&base->gpwrdn;
mem_addr_t pcgcctl_reg = (mem_addr_t)&base->pcgcctl;
Expand Down Expand Up @@ -1819,9 +1722,8 @@ static int dwc2_core_soft_reset(const struct device *dev)

static int udc_dwc2_init_controller(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;
struct udc_dwc2_data *const priv = udc_get_private(dev);
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
mem_addr_t grxfsiz_reg = (mem_addr_t)&base->grxfsiz;
mem_addr_t gahbcfg_reg = (mem_addr_t)&base->gahbcfg;
mem_addr_t gusbcfg_reg = (mem_addr_t)&base->gusbcfg;
Expand Down Expand Up @@ -2228,6 +2130,8 @@ static int dwc2_driver_preinit(const struct device *dev)
uint32_t ineps;
int err;

DEVICE_MMIO_NAMED_MAP(dev, base, K_MEM_CACHE_NONE);

k_mutex_init(&data->mutex);

k_event_init(&priv->drv_evt);
Expand Down Expand Up @@ -2417,7 +2321,7 @@ static inline int dwc2_read_fifo_setup(const struct device *dev, uint8_t ep,
/* FIFO access is always in 32-bit words */

if (size != 8) {
LOG_ERR("%d bytes SETUP", size);
LOG_ERR("%zu bytes SETUP", size);
}

/*
Expand Down Expand Up @@ -2708,8 +2612,8 @@ static inline void dwc2_handle_oepint(const struct device *dev)
* which allows common SETUP interrupt handling.
*/
addr = sys_read32((mem_addr_t)&base->out_ep[0].doepdma);
sys_cache_data_invd_range((void *)(addr - 8), 8);
memcpy(priv->setup, (void *)(addr - 8), sizeof(priv->setup));
sys_cache_data_invd_range(UINT_TO_POINTER(addr - 8), 8);
memcpy(priv->setup, UINT_TO_POINTER(addr - 8), sizeof(priv->setup));
}

if (status & USB_DWC2_DOEPINT_SETUP) {
Expand Down Expand Up @@ -2770,8 +2674,7 @@ static inline void dwc2_handle_oepint(const struct device *dev)
*/
static void dwc2_handle_incompisoin(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
struct udc_dwc2_data *const priv = udc_get_private(dev);
mem_addr_t gintsts_reg = (mem_addr_t)&base->gintsts;
const uint32_t mask =
Expand Down Expand Up @@ -2819,8 +2722,7 @@ static void dwc2_handle_incompisoin(const struct device *dev)
*/
static void dwc2_handle_incompisoout(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
struct udc_dwc2_data *const priv = udc_get_private(dev);
mem_addr_t gintsts_reg = (mem_addr_t)&base->gintsts;
const uint32_t mask =
Expand Down Expand Up @@ -2865,8 +2767,7 @@ static void dwc2_handle_incompisoout(const struct device *dev)

static void dwc2_handle_goutnakeff(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
struct udc_dwc2_data *const priv = udc_get_private(dev);
k_spinlock_key_t key;
mem_addr_t doepctl_reg;
Expand Down Expand Up @@ -2933,8 +2834,7 @@ static void dwc2_handle_goutnakeff(const struct device *dev)

static void udc_dwc2_isr_handler(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;
struct usb_dwc2_reg *const base = config->base;
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
struct udc_dwc2_data *const priv = udc_get_private(dev);
mem_addr_t gintsts_reg = (mem_addr_t)&base->gintsts;
uint32_t int_status;
Expand Down Expand Up @@ -3290,9 +3190,10 @@ static const struct udc_api udc_dwc2_api = {
.ep_dequeue = udc_dwc2_ep_dequeue,
};

#define UDC_DWC2_DT_INST_REG_ADDR(n) \
COND_CODE_1(DT_NUM_REGS(DT_DRV_INST(n)), (DT_INST_REG_ADDR(n)), \
(DT_INST_REG_ADDR_BY_NAME(n, core)))
#define UDC_DWC2_ROM_INITIALIZER(node_id) \
COND_CODE_1(DT_NUM_REGS(node_id), \
(Z_DEVICE_MMIO_ROM_INITIALIZER(node_id)), \
(Z_DEVICE_MMIO_NAMED_ROM_INITIALIZER(core, node_id)))

#if !defined(UDC_DWC2_IRQ_DT_INST_DEFINE)
#define UDC_DWC2_IRQ_FLAGS_TYPE0(n) 0
Expand Down Expand Up @@ -3368,7 +3269,7 @@ static const struct udc_api udc_dwc2_api = {
.ep_cfg_in = ep_cfg_in, \
.ep_cfg_out = ep_cfg_out, \
.make_thread = udc_dwc2_make_thread_##n, \
.base = (struct usb_dwc2_reg *)UDC_DWC2_DT_INST_REG_ADDR(n), \
.base = UDC_DWC2_ROM_INITIALIZER(DT_DRV_INST(n)), \
.pcfg = UDC_DWC2_PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
.irq_enable_func = udc_dwc2_irq_enable_func_##n, \
.irq_disable_func = udc_dwc2_irq_disable_func_##n, \
Expand Down
98 changes: 97 additions & 1 deletion drivers/usb/udc/udc_dwc2.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct udc_dwc2_config {
size_t num_out_eps;
struct udc_ep_config *ep_cfg_in;
struct udc_ep_config *ep_cfg_out;
struct usb_dwc2_reg *const base;
DEVICE_MMIO_NAMED_ROM(base);
/* Pointer to pin control configuration or NULL */
struct pinctrl_dev_config *const pcfg;
/* Pointer to vendor quirks or NULL */
Expand All @@ -55,6 +55,102 @@ struct udc_dwc2_config {
uint32_t ghwcfg4;
};

enum dwc2_suspend_type {
DWC2_SUSPEND_NO_POWER_SAVING,
DWC2_SUSPEND_HIBERNATION,
};

/* Registers that have to be stored before Partial Power Down or Hibernation */
struct dwc2_reg_backup {
uint32_t gotgctl;
uint32_t gahbcfg;
uint32_t gusbcfg;
uint32_t gintmsk;
uint32_t grxfsiz;
uint32_t gnptxfsiz;
uint32_t gi2cctl;
uint32_t glpmcfg;
uint32_t gdfifocfg;
union {
uint32_t dptxfsiz[15];
uint32_t dieptxf[15];
};
uint32_t dcfg;
uint32_t dctl;
uint32_t diepmsk;
uint32_t doepmsk;
uint32_t daintmsk;
uint32_t diepctl[16];
uint32_t dieptsiz[16];
uint32_t diepdma[16];
uint32_t doepctl[16];
uint32_t doeptsiz[16];
uint32_t doepdma[16];
uint32_t pcgcctl;
};


/* Driver private data per instance */
struct udc_dwc2_data {
DEVICE_MMIO_NAMED_RAM(base);
struct k_spinlock lock;
struct k_thread thread_data;
/* Main events the driver thread waits for */
struct k_event drv_evt;
/* Endpoint is considered disabled when there is no active transfer */
struct k_event ep_disabled;
/* Transfer triggers (IN on bits 0-15, OUT on bits 16-31) */
atomic_t xfer_new;
/* Finished transactions (IN on bits 0-15, OUT on bits 16-31) */
atomic_t xfer_finished;
struct dwc2_reg_backup backup;
uint32_t ghwcfg1;
uint32_t max_xfersize;
uint32_t max_pktcnt;
uint32_t tx_len[16];
uint32_t rx_siz[16];
/* Isochronous endpoint enabled (IN on bits 0-15, OUT on bits 16-31) */
uint32_t iso_enabled;
uint16_t iso_in_rearm;
uint16_t iso_out_rearm;
uint16_t ep_out_disable;
uint16_t ep_out_stall;
uint16_t txf_set;
uint16_t pending_tx_flush;
uint16_t dfifodepth;
uint16_t rxfifo_depth;
uint16_t max_txfifo_depth[16];
uint16_t sof_num;
/* Configuration flags */
unsigned int dynfifosizing : 1;
unsigned int bufferdma : 1;
unsigned int syncrst : 1;
/* Defect workarounds */
unsigned int wa_essregrestored : 1;
/* Runtime state flags */
unsigned int hibernated : 1;
unsigned int enumdone : 1;
unsigned int enumspd : 2;
unsigned int ignore_ep0_nakeff : 1;
enum dwc2_suspend_type suspend_type;
/* Number of endpoints including control endpoint */
uint8_t numdeveps;
/* Number of IN endpoints including control endpoint */
uint8_t ineps;
/* Number of OUT endpoints including control endpoint */
uint8_t outeps;
uint8_t setup[8];
};

/* Required by DEVICE_MMIO_NAMED_* macros */
#define DEV_CFG(_dev) ((const struct udc_dwc2_config *)(_dev)->config)
#define DEV_DATA(_dev) ((struct udc_dwc2_data *)(udc_get_private(_dev)))

static inline struct usb_dwc2_reg *dwc2_get_base(const struct device *dev)
{
return (struct usb_dwc2_reg *)DEVICE_MMIO_NAMED_GET(dev, base);
}

#include "udc_dwc2_vendor_quirks.h"

#define UDC_DWC2_VENDOR_QUIRK_GET(n) \
Expand Down
Loading
Loading