Skip to content
13 changes: 13 additions & 0 deletions include/unicore-mx/common/dwc_otg.ucd
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ bit SRQ 1
bit SRQSCS 0

reg GOTGINT 0x004
% Session end detected. The core sets this bit to indicate that the level of the voltage
% on VBUS is no longer valid for a B-Peripheral session when VBUS < 0.8 V //STM32F4
bit SEDET 2

% OTG AHB configuration register
reg GAHBCFG 0x008
Expand Down Expand Up @@ -847,6 +850,16 @@ bits XFRSIZ 7 0

% Power and clock gating control and status register
reg PCGCCTL 0xE00
% Stop PHY clock. The application sets this bit to stop the PHY clock when the USB is suspended, the session
% is not valid, or the device is disconnected.
% The application clears this bit when the USB is resumed or a new session starts //STM32F4
bit STPPCLK 0
% Gate HCLK. The application sets this bit to gate HCLK to modules other than the AHB Slave and Master
% and wakeup logic when the USB is suspended or the session is not valid.
% The application clears this bit when the USB is resumed or a new session starts. //STM32F4
bit GATEHCLK 1
% Indicates that the PHY has been suspended.
bit PHYSUSP 4

% Data FIFO
register
Expand Down
57 changes: 49 additions & 8 deletions include/unicore-mx/usbd/usbd.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ enum usbd_speed {

typedef enum usbd_speed usbd_speed;

/** Optional features */
enum usbd_backend_features{
USBD_FEATURE_NONE = 0
, USBD_PHY_EXT = (1 << 0)
, USBD_VBUS_SENSE = (1 << 1)
, USBD_VBUS_EXT = (1 << 2)
//* provide usb-core auto power-up/down on connect/disconnect
, USBD_USE_POWERDOWN = (1 << 3)
};

struct usbd_backend_config {
/** Number of endpoints. (Including control endpoint) */
uint8_t ep_count;
Expand All @@ -145,13 +155,8 @@ struct usbd_backend_config {
/** Device speed */
usbd_speed speed;

/** Optional features */
enum {
USBD_FEATURE_NONE = 0,
USBD_PHY_EXT = (1 << 0),
USBD_VBUS_SENSE = (1 << 1),
USBD_VBUS_EXT = (1 << 2)
} feature;
/** Optional features see usbd_backend_features*/
unsigned int feature;
};

typedef struct usbd_backend_config usbd_backend_config;
Expand Down Expand Up @@ -279,7 +284,7 @@ enum usbd_transfer_flags {
USBD_FLAG_PACKET_PER_FRAME_MASK = (0x3 << 5)
};

typedef enum usbd_transfer_flags usbd_transfer_flags;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possibly ive got a warning here? enum and typedef - with same name. its confusing me, i newer see such trick.
i`ve saw overriding enum item name with macro definition, but override enum by typedef - is it vlalid practice for C?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

@alexrayne alexrayne May 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, i know about namespaces, and that code was compiled succesfully.
when i ask about "valid practice for C" i mean - is it good? is it helpful? can it lead to some errors?
the name "usbd_transfer_flags" imho nott very suitable for enum. such name also can be imagine for struct of a binary set of flags.
anyway, if you insist - let`s revert this typedef back to code.

Copy link
Author

@alexrayne alexrayne May 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you forgot to denote
+typedef unsigned char usbd_transfer_flags;
ARMCC compiler generates warning when we try to assign to enum variable integer value (with set of flags).
therefore i denote for usbd_transfer_flags as numeric type

typedef unsigned char usbd_transfer_flags;

/**
* USB Transfer status
Expand Down Expand Up @@ -431,6 +436,8 @@ typedef void (*usbd_set_interface_callback)(usbd_device *dev,
typedef void (*usbd_setup_callback)(usbd_device *dev, uint8_t addr,
const struct usb_setup_data *setup_data);

typedef void (* usbd_session_callback)(usbd_device *dev, bool online);

typedef void (* usbd_generic_callback)(usbd_device *dev);

/**
Expand Down Expand Up @@ -515,6 +522,16 @@ void usbd_register_resume_callback(usbd_device *dev,
void usbd_register_sof_callback(usbd_device *dev,
usbd_generic_callback callback);

/**
* Register session connect/disconnect callback
* with USBD_VBUS_SENSE feature primary need for cable
* plug detection
* @param[in] dev USB Device
* @param[in] callback callback to be invoked
*/
void usbd_register_session_callback(usbd_device *dev,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

session callback facility look like a good idea.

usbd_session_callback callback);

/**
* Register SET_CONFIGURATION callback \n
* stack will invoke @a callback when ever SET_CONFIGURATION is received
Expand Down Expand Up @@ -643,6 +660,30 @@ uint8_t usbd_get_address(usbd_device *dev);
*/
usbd_speed usbd_get_speed(usbd_device *dev);


/**
* Get status of connected cable.
* @param[in] dev USB Device
* @return true - cable connected, and Vbus active
*/
bool usbd_is_vbus(usbd_device *dev);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ability to know VBUS state also look like a good idea too.


/**
* Controls power state of usb-core and PHY
* @param[in] dev USB Device
* @param[in] onoff - true turn on device in action, and power PHY
* false disconnects, disable PHY and stops usb-core
*/
void usbd_enable(usbd_device *dev, bool onoff);

/**
* Checks power state of usb-core and PHY
* @param[in] dev USB Device
* @param[in] \return true - device in action, and power PHY
* false - disabled PHY and stops usb-core
*/
bool usbd_is_enabled(usbd_device *dev);

/**
* Perform a transfer
*
Expand Down
1 change: 1 addition & 0 deletions lib/usbd/backend/dwc_otg_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct dwc_otg_private_data {
#define USBD_DEVICE_EXTRA \
struct dwc_otg_private_data private_data;

//#include "../usbd_private.h"
void dwc_otg_init(usbd_device *dev);

void dwc_otg_set_address(usbd_device *dev, uint8_t addr);
Expand Down
25 changes: 22 additions & 3 deletions lib/usbd/backend/usbd_dwc_otg.c
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,8 @@ static inline void alloc_fifo_for_ep0_only(usbd_device *dev)

void dwc_otg_poll(usbd_device *dev)
{
if (usbd_is_enabled(dev)){

if (REBASE(DWC_OTG_GINTSTS) & DWC_OTG_GINTSTS_ENUMDNE) {
REBASE(DWC_OTG_DCFG) &= ~DWC_OTG_DCFG_DAD_MASK;
disable_all_non_ep0(dev);
Expand Down Expand Up @@ -1033,14 +1035,31 @@ void dwc_otg_poll(usbd_device *dev)
usbd_handle_suspend(dev);
}

if (REBASE(DWC_OTG_GINTSTS) & DWC_OTG_GINTSTS_SOF) {
REBASE(DWC_OTG_GINTSTS) = DWC_OTG_GINTSTS_SOF;
usbd_handle_sof(dev);
}

} //if (usbd_is_enabled(dev))
else
REBASE(DWC_OTG_GINTSTS) = DWC_OTG_GINTSTS_ENUMDNE | DWC_OTG_GINTSTS_USBRST
| DWC_OTG_GINTSTS_RXFLVL
| DWC_OTG_GINTSTS_IEPINT | DWC_OTG_GINTSTS_OEPINT
| DWC_OTG_GINTSTS_SOF
| DWC_OTG_GINTSTS_USBSUSP | DWC_OTG_GINTSTS_ESUSP;

if (REBASE(DWC_OTG_GINTSTS) & DWC_OTG_GINTSTS_WKUPINT) {
REBASE(DWC_OTG_GINTSTS) = DWC_OTG_GINTSTS_WKUPINT;
usbd_handle_resume(dev);
}

if (REBASE(DWC_OTG_GINTSTS) & DWC_OTG_GINTSTS_SOF) {
REBASE(DWC_OTG_GINTSTS) = DWC_OTG_GINTSTS_SOF;
usbd_handle_sof(dev);
if ( (REBASE(DWC_OTG_GINTSTS) & (DWC_OTG_GINTSTS_SRQINT)) != 0) {
REBASE(DWC_OTG_GINTSTS) = (DWC_OTG_GINTSTS_SRQINT);
usbd_handle_session(dev, true);
}
if ( (REBASE(DWC_OTG_GOTGINT) & (DWC_OTG_GOTGINT_SEDET)) != 0) {
REBASE(DWC_OTG_GOTGINT) = DWC_OTG_GOTGINT_SEDET;
usbd_handle_session(dev, false);
}
}

Expand Down
61 changes: 58 additions & 3 deletions lib/usbd/backend/usbd_stm32_otg_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include <unicore-mx/usbd/usbd.h>

static usbd_device *init(const usbd_backend_config *config);
static bool otgfs_is_powered(usbd_device *dev);
static usbd_power_status otgfs_power_control(usbd_device *dev, usbd_power_action action);

static struct usbd_device _usbd_dev;

Expand All @@ -51,6 +53,8 @@ const struct usbd_backend usbd_stm32_otg_fs = {
.get_speed = dwc_otg_get_speed,
.set_address_before_status = true,
.base_address = USB_OTG_FS_BASE,
.is_vbus = otgfs_is_powered
, .power_control = otgfs_power_control
};

#define REBASE(REG, ...) REG(usbd_stm32_otg_fs.base_address, ##__VA_ARGS__)
Expand All @@ -74,16 +78,20 @@ static usbd_device *init(const usbd_backend_config *config)
_usbd_dev.backend = &usbd_stm32_otg_fs;
_usbd_dev.config = config;

//* stm32f4 use FS CID=0x1100, HS CID=0x02000600
//* stm32f7 0x3000, CID=0x00003100
const unsigned otg_hs_cid_boundary = 0x3100;

if (config->feature & USBD_VBUS_SENSE) {
if (OTG_FS_CID >= 0x00002000) { /* 2.0 */
if (OTG_FS_CID >= otg_hs_cid_boundary) { /* 2.0 HS core*/
/* Enable VBUS detection */
OTG_FS_GCCFG |= OTG_GCCFG_VBDEN;
} else { /* 1.x */
} else { /* 1.x FS core*/
/* Enable VBUS sensing in device mode */
OTG_FS_GCCFG |= OTG_GCCFG_VBUSBSEN;
}
} else {
if (OTG_FS_CID >= 0x00002000) { /* 2.0 */
if (OTG_FS_CID >= otg_hs_cid_boundary) { /* 2.0 */
/* Disable VBUS detection. */
OTG_FS_GCCFG &= ~OTG_GCCFG_VBDEN;
REBASE(DWC_OTG_GOTGCTL) |= DWC_OTG_GOTGCTL_BVALOEN |
Expand All @@ -108,3 +116,50 @@ static usbd_device *init(const usbd_backend_config *config)

return &_usbd_dev;
}

static
bool otgfs_is_powered(usbd_device *dev){
uint32_t base = dev->backend->base_address;
return (DWC_OTG_GOTGCTL(base) & DWC_OTG_GOTGCTL_BSVLD) != 0;
}

static
usbd_power_status otgfs_power_control(usbd_device *dev, usbd_power_action action){
uint32_t base = dev->backend->base_address;
switch (action){
case usbd_paActivate:{
DWC_OTG_PCGCCTL(base) = 0;
OTG_FS_GCCFG |= OTG_GCCFG_PWRDWN;
REBASE(DWC_OTG_GINTMSK) |= DWC_OTG_GINTMSK_ENUMDNEM | DWC_OTG_GINTSTS_USBSUSP
| DWC_OTG_GINTMSK_RXFLVLM | DWC_OTG_GINTMSK_IEPINT ;
break;
}
case usbd_paShutdown: {
/* Wait for AHB idle. */
uint32_t save_dis = REBASE(DWC_OTG_DCTL) & DWC_OTG_DCTL_SDIS;
//disable device connection before poweroff
REBASE(DWC_OTG_DCTL) |= DWC_OTG_DCTL_SDIS;
while (( (DWC_OTG_GRSTCTL(base) & DWC_OTG_GRSTCTL_AHBIDL) == 0) );
//* drop ISRs, cause stoped Core cant handle them
REBASE(DWC_OTG_GINTSTS) = ~( DWC_OTG_GINTSTS_USBSUSP
| DWC_OTG_GINTSTS_WKUPINT
| DWC_OTG_GINTSTS_SRQINT
);
REBASE(DWC_OTG_GINTMSK) &= ~( DWC_OTG_GINTMSK_ENUMDNEM
| DWC_OTG_GINTMSK_RXFLVLM | DWC_OTG_GINTMSK_IEPINT
);
//poser down PHY
OTG_FS_GCCFG &= ~OTG_GCCFG_PWRDWN;
DWC_OTG_PCGCCTL(base) = DWC_OTG_PCGCCTL_STPPCLK; //| DWC_OTG_PCGCCTL_GATEHCLK ;
//destore connection disable state after PHY poweroff
REBASE(DWC_OTG_DCTL) |= save_dis;
break;
}
}
usbd_power_status res = 0;
if ( (DWC_OTG_PCGCCTL(base) & DWC_OTG_PCGCCTL_PHYSUSP) == 0)
res |= usbd_psPHYOn;
if ((OTG_FS_GCCFG & OTG_GCCFG_PWRDWN) != 0)
res |= usbd_psCoreEnabled;
return res;
}
43 changes: 43 additions & 0 deletions lib/usbd/usbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ void usbd_register_sof_callback(usbd_device *dev,
}
}

void usbd_register_session_callback(usbd_device *dev,
usbd_session_callback callback)
{
dev->callback.session = callback;
}



/* Functions to be provided by the hardware abstraction layer */
void usbd_poll(usbd_device *dev, uint32_t us)
{
Expand All @@ -145,9 +153,21 @@ void usbd_poll(usbd_device *dev, uint32_t us)

void usbd_disconnect(usbd_device *dev, bool disconnect)
{
if (!disconnect) {
// power-up on connect
if ( ((dev->config->feature & USBD_USE_POWERDOWN) != 0)
&& (dev->backend->power_control) )
dev->backend->power_control(dev, usbd_paActivate);
}
if (dev->backend->disconnect) {
dev->backend->disconnect(dev, disconnect);
}
if (disconnect) {
// power-down after disconnect
if ( ((dev->config->feature & USBD_USE_POWERDOWN) != 0)
&& (dev->backend->power_control) )
dev->backend->power_control(dev, usbd_paShutdown );
}
}

void usbd_ep_prepare(usbd_device *dev, uint8_t addr, usbd_ep_type type,
Expand Down Expand Up @@ -208,5 +228,28 @@ usbd_speed usbd_get_speed(usbd_device *dev)
return dev->backend->get_speed(dev);
}

bool usbd_is_vbus(usbd_device *dev){
if (dev->backend->is_vbus)
return dev->backend->is_vbus(dev);
else
return true;
}

void usbd_enable(usbd_device *dev, bool onoff){
if (dev->backend->power_control)
dev->backend->power_control(dev, (onoff)? usbd_paActivate : usbd_paShutdown );
else
// try emulate enable via disconnect
usbd_disconnect(dev, !onoff);
}

bool usbd_is_enabled(usbd_device *dev){
if (dev->backend->power_control)
return dev->backend->power_control(dev, usbd_paCheck ) == usbd_psOn;
else
return true;
}


/**@}*/

Loading