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
60 changes: 52 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
Copy link
Contributor

Choose a reason for hiding this comment

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

"//*" (IMO) Please C style comment only (code consistancy).
@danielinux @brabo what do you think?

, 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,33 @@ 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
* !!! warning: enable(false) - sets core to disconnected state, but
* enable(true) - not automaticaly release disconnected status,
* it should be set by disconnect(false)
*/
void usbd_enable(usbd_device *dev, bool onoff);

Copy link
Contributor

Choose a reason for hiding this comment

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

There is already a function, see "void usbd_disconnect(usbd_device *dev, bool disconnected);".

Copy link
Author

@alexrayne alexrayne Feb 4, 2017

Choose a reason for hiding this comment

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

usbd_disconnect stops session, it is not control power mode of core or phy.

/**
* 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
56 changes: 53 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*/
Copy link
Contributor

Choose a reason for hiding this comment

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

OTG_FS_CID >= 0x00003000 leads to running 1.0 HS core init code on 2.0 HS core init

/* 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,45 @@ 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. */
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 ;
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 (!onoff)
usbd_disconnect(dev, true);
else
if (dev->backend->power_control)
dev->backend->power_control(dev, (onoff)? usbd_paActivate : usbd_paShutdown );
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Application code
= usbd_disconnect(dev, true)
== dev->backend->disconnect(dev, true);
== usbd_enable(dev, false);
=== usbd_disconnect(dev, false);
==== usbd_enable(dev, true);
===== dev->backend->power_control(dev, usbd_paActivate);
==== dev->backend->disconnect(dev, false);
=== dev->backend->power_control(dev, usbd_paShutdown );

Look at the flow of control.
At the end, NOT disconnected with SHUTDOWN power control.

Copy link
Author

Choose a reason for hiding this comment

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

don`t understand you - enable(false) MUST not shutdown?

Copy link
Author

Choose a reason for hiding this comment

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

oh, i see, thank you

Copy link
Contributor

Choose a reason for hiding this comment

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

for your new code.

=usbd_disconnect(dev, true)   <----------------\
==dev->backend->disconnect(dev, true);         | RECURSIVE CALL! STACK OVERFLOW!
==usbd_enable(dev, false);                     |
===usbd_disconnect(dev, true)   ---------------/
===dev->backend->power_control(dev, usbd_paShutdown);

Copy link
Author

Choose a reason for hiding this comment

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

yeah, see alredy. more trouble now bother me - cantt understand how to wake up FS from powerdown, cause it want normaly detect online and reset after ungating core clock

Copy link
Author

Choose a reason for hiding this comment

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

well, resolve it. but not preferable way - not like what i write

Copy link
Contributor

Choose a reason for hiding this comment

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

When usbd_enable(dev, false) is called, it disconnect and shutdown. but when usbd_enable(dev, true) is called, it only power-up (it remove the disconnect condition).

Copy link
Author

@alexrayne alexrayne May 26, 2017

Choose a reason for hiding this comment

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

yes, this was confused me too. disconnection MUST be provided before powerdown. but fro stm DWC core it is mean that USB enter to non-connectable state. imho, name 'disconnect' - not very suitable for this operation.
i`ll change behaviour to restore disconnection state on powerdown complete.
i not sure, is it good to place disconnection before powerdown into backend->power_control, instead of botherig it on frontend?


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