Skip to content

USBD add core-power and Vbus handle #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
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