Several Cadence3 improvements are introduced in v5.13-rc1:
- Add recovery during resume if the controller was lost power at system suspend - Reduce DMA memory footprint - Other small improvements -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEDaZUZmFxRG/wNThrSFkpgVDWcbsFAmB0S50ACgkQSFkpgVDW cbthMggAnH0oPq93dipS9g2WhHxmwKGJimWTFU82RxuuX6MefvllXEkWCHJdPplp dyKhzaFQxFksR7GJ8UCoZg3wg0rk38suLiN+W+k9re6QaHPFWJiMEm83mN3/YaNn stVLiuMRl+VIApIIWbf3MW8/a3j9N5oRI+MbqmvhcA4TFu3Z1xTe9xhs8eDtzeUV cGI6JbrZr5Q3pcsvvZPwj2nFgjJ7eYum9Z1CsAopHyVnYu/NK2jh2+W+L37dUSan cwUOIRoNvSYNHyXFVszOEmfxtTAKiISQ7L4+8tXr4X+qC8tUNd8Rw1ow5BAo8gh+ bBL8+NZVVGoTvNpYPhLLUHncE5Fn9Q== =+ZMP -----END PGP SIGNATURE----- Merge tag 'usb-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb into usb-next Peter writes: Several Cadence3 improvements are introduced in v5.13-rc1: - Add recovery during resume if the controller was lost power at system suspend - Reduce DMA memory footprint - Other small improvements * tag 'usb-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb: usb: cdnsp: Fixes issue with Configure Endpoint command usb: cdnsp: remove redundant initialization of variable ret usb: cdns3: delete repeated clear operations usb: cdns3: Optimize DMA request buffer allocation usb: cdns3: Use dma_pool_* api to alloc trb pool usb: cdns3: fix static checker warning. usb: cdns3: imx: mark cdns_imx_system_resume as __maybe_unused usb: cdns3: trace: delete the trace parameter for request->trb usb: cdns3: imx: add power lost support for system resume usb: cdns3: add power lost support for system resume
This commit is contained in:
Коммит
9bc46a12c5
|
@ -59,6 +59,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include "core.h"
|
||||
|
@ -190,29 +191,13 @@ dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep,
|
|||
return priv_ep->trb_pool_dma + offset;
|
||||
}
|
||||
|
||||
static int cdns3_ring_size(struct cdns3_endpoint *priv_ep)
|
||||
{
|
||||
switch (priv_ep->type) {
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
return TRB_ISO_RING_SIZE;
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
return TRB_CTRL_RING_SIZE;
|
||||
default:
|
||||
if (priv_ep->use_streams)
|
||||
return TRB_STREAM_RING_SIZE;
|
||||
else
|
||||
return TRB_RING_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep)
|
||||
{
|
||||
struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
|
||||
|
||||
if (priv_ep->trb_pool) {
|
||||
dma_free_coherent(priv_dev->sysdev,
|
||||
cdns3_ring_size(priv_ep),
|
||||
priv_ep->trb_pool, priv_ep->trb_pool_dma);
|
||||
dma_pool_free(priv_dev->eps_dma_pool,
|
||||
priv_ep->trb_pool, priv_ep->trb_pool_dma);
|
||||
priv_ep->trb_pool = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +211,7 @@ static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep)
|
|||
int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep)
|
||||
{
|
||||
struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
|
||||
int ring_size = cdns3_ring_size(priv_ep);
|
||||
int ring_size = TRB_RING_SIZE;
|
||||
int num_trbs = ring_size / TRB_SIZE;
|
||||
struct cdns3_trb *link_trb;
|
||||
|
||||
|
@ -234,10 +219,10 @@ int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep)
|
|||
cdns3_free_trb_pool(priv_ep);
|
||||
|
||||
if (!priv_ep->trb_pool) {
|
||||
priv_ep->trb_pool = dma_alloc_coherent(priv_dev->sysdev,
|
||||
ring_size,
|
||||
&priv_ep->trb_pool_dma,
|
||||
GFP_DMA32 | GFP_ATOMIC);
|
||||
priv_ep->trb_pool = dma_pool_alloc(priv_dev->eps_dma_pool,
|
||||
GFP_DMA32 | GFP_ATOMIC,
|
||||
&priv_ep->trb_pool_dma);
|
||||
|
||||
if (!priv_ep->trb_pool)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -834,9 +819,15 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
|
|||
priv_ep->dir);
|
||||
|
||||
if ((priv_req->flags & REQUEST_UNALIGNED) &&
|
||||
priv_ep->dir == USB_DIR_OUT && !request->status)
|
||||
priv_ep->dir == USB_DIR_OUT && !request->status) {
|
||||
/* Make DMA buffer CPU accessible */
|
||||
dma_sync_single_for_cpu(priv_dev->sysdev,
|
||||
priv_req->aligned_buf->dma,
|
||||
priv_req->aligned_buf->size,
|
||||
priv_req->aligned_buf->dir);
|
||||
memcpy(request->buf, priv_req->aligned_buf->buf,
|
||||
request->length);
|
||||
}
|
||||
|
||||
priv_req->flags &= ~(REQUEST_PENDING | REQUEST_UNALIGNED);
|
||||
/* All TRBs have finished, clear the counter */
|
||||
|
@ -898,8 +889,8 @@ static void cdns3_free_aligned_request_buf(struct work_struct *work)
|
|||
* interrupts.
|
||||
*/
|
||||
spin_unlock_irqrestore(&priv_dev->lock, flags);
|
||||
dma_free_coherent(priv_dev->sysdev, buf->size,
|
||||
buf->buf, buf->dma);
|
||||
dma_free_noncoherent(priv_dev->sysdev, buf->size,
|
||||
buf->buf, buf->dma, buf->dir);
|
||||
kfree(buf);
|
||||
spin_lock_irqsave(&priv_dev->lock, flags);
|
||||
}
|
||||
|
@ -926,10 +917,13 @@ static int cdns3_prepare_aligned_request_buf(struct cdns3_request *priv_req)
|
|||
return -ENOMEM;
|
||||
|
||||
buf->size = priv_req->request.length;
|
||||
buf->dir = usb_endpoint_dir_in(priv_ep->endpoint.desc) ?
|
||||
DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
|
||||
buf->buf = dma_alloc_coherent(priv_dev->sysdev,
|
||||
buf->buf = dma_alloc_noncoherent(priv_dev->sysdev,
|
||||
buf->size,
|
||||
&buf->dma,
|
||||
buf->dir,
|
||||
GFP_ATOMIC);
|
||||
if (!buf->buf) {
|
||||
kfree(buf);
|
||||
|
@ -951,10 +945,17 @@ static int cdns3_prepare_aligned_request_buf(struct cdns3_request *priv_req)
|
|||
}
|
||||
|
||||
if (priv_ep->dir == USB_DIR_IN) {
|
||||
/* Make DMA buffer CPU accessible */
|
||||
dma_sync_single_for_cpu(priv_dev->sysdev,
|
||||
buf->dma, buf->size, buf->dir);
|
||||
memcpy(buf->buf, priv_req->request.buf,
|
||||
priv_req->request.length);
|
||||
}
|
||||
|
||||
/* Transfer DMA buffer ownership back to device */
|
||||
dma_sync_single_for_device(priv_dev->sysdev,
|
||||
buf->dma, buf->size, buf->dir);
|
||||
|
||||
priv_req->flags |= REQUEST_UNALIGNED;
|
||||
trace_cdns3_prepare_aligned_request(priv_req);
|
||||
|
||||
|
@ -3103,9 +3104,10 @@ static void cdns3_gadget_exit(struct cdns *cdns)
|
|||
struct cdns3_aligned_buf *buf;
|
||||
|
||||
buf = cdns3_next_align_buf(&priv_dev->aligned_buf_list);
|
||||
dma_free_coherent(priv_dev->sysdev, buf->size,
|
||||
dma_free_noncoherent(priv_dev->sysdev, buf->size,
|
||||
buf->buf,
|
||||
buf->dma);
|
||||
buf->dma,
|
||||
buf->dir);
|
||||
|
||||
list_del(&buf->list);
|
||||
kfree(buf);
|
||||
|
@ -3113,6 +3115,7 @@ static void cdns3_gadget_exit(struct cdns *cdns)
|
|||
|
||||
dma_free_coherent(priv_dev->sysdev, 8, priv_dev->setup_buf,
|
||||
priv_dev->setup_dma);
|
||||
dma_pool_destroy(priv_dev->eps_dma_pool);
|
||||
|
||||
kfree(priv_dev->zlp_buf);
|
||||
usb_put_gadget(&priv_dev->gadget);
|
||||
|
@ -3185,6 +3188,14 @@ static int cdns3_gadget_start(struct cdns *cdns)
|
|||
/* initialize endpoint container */
|
||||
INIT_LIST_HEAD(&priv_dev->gadget.ep_list);
|
||||
INIT_LIST_HEAD(&priv_dev->aligned_buf_list);
|
||||
priv_dev->eps_dma_pool = dma_pool_create("cdns3_eps_dma_pool",
|
||||
priv_dev->sysdev,
|
||||
TRB_RING_SIZE, 8, 0);
|
||||
if (!priv_dev->eps_dma_pool) {
|
||||
dev_err(priv_dev->dev, "Failed to create TRB dma pool\n");
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
ret = cdns3_init_eps(priv_dev);
|
||||
if (ret) {
|
||||
|
@ -3235,6 +3246,8 @@ err3:
|
|||
err2:
|
||||
cdns3_free_all_eps(priv_dev);
|
||||
err1:
|
||||
dma_pool_destroy(priv_dev->eps_dma_pool);
|
||||
|
||||
usb_put_gadget(&priv_dev->gadget);
|
||||
cdns->gadget_dev = NULL;
|
||||
return ret;
|
||||
|
@ -3304,6 +3317,8 @@ static int cdns3_gadget_resume(struct cdns *cdns, bool hibernated)
|
|||
return 0;
|
||||
|
||||
cdns3_gadget_config(priv_dev);
|
||||
if (hibernated)
|
||||
writel(USB_CONF_DEVEN, &priv_dev->regs->usb_conf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef __LINUX_CDNS3_GADGET
|
||||
#define __LINUX_CDNS3_GADGET
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/dma-direction.h>
|
||||
|
||||
/*
|
||||
* USBSS-DEV register interface.
|
||||
|
@ -1205,6 +1206,7 @@ struct cdns3_aligned_buf {
|
|||
void *buf;
|
||||
dma_addr_t dma;
|
||||
u32 size;
|
||||
enum dma_data_direction dir;
|
||||
unsigned in_use:1;
|
||||
struct list_head list;
|
||||
};
|
||||
|
@ -1298,6 +1300,7 @@ struct cdns3_device {
|
|||
|
||||
struct cdns3_usb_regs __iomem *regs;
|
||||
|
||||
struct dma_pool *eps_dma_pool;
|
||||
struct usb_ctrlrequest *setup_buf;
|
||||
dma_addr_t setup_dma;
|
||||
void *zlp_buf;
|
||||
|
|
|
@ -361,6 +361,39 @@ static int cdns_imx_suspend(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Indicate if the controller was power lost before */
|
||||
static inline bool cdns_imx_is_power_lost(struct cdns_imx *data)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = cdns_imx_readl(data, USB3_CORE_CTRL1);
|
||||
if ((value & SW_RESET_MASK) == ALL_SW_RESET)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __maybe_unused cdns_imx_system_resume(struct device *dev)
|
||||
{
|
||||
struct cdns_imx *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = cdns_imx_resume(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cdns_imx_is_power_lost(data)) {
|
||||
dev_dbg(dev, "resume from power lost\n");
|
||||
ret = cdns_imx_noncore_init(data);
|
||||
if (ret)
|
||||
cdns_imx_suspend(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
static int cdns_imx_platform_suspend(struct device *dev,
|
||||
bool suspend, bool wakeup)
|
||||
|
@ -372,6 +405,7 @@ static int cdns_imx_platform_suspend(struct device *dev,
|
|||
|
||||
static const struct dev_pm_ops cdns_imx_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(cdns_imx_suspend, cdns_imx_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(cdns_imx_suspend, cdns_imx_system_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id cdns_imx_of_match[] = {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "core.h"
|
||||
#include "gadget-export.h"
|
||||
#include "drd.h"
|
||||
|
||||
static int set_phy_power_on(struct cdns *cdns)
|
||||
{
|
||||
|
@ -236,6 +237,18 @@ static int cdns3_controller_resume(struct device *dev, pm_message_t msg)
|
|||
if (!cdns->in_lpm)
|
||||
return 0;
|
||||
|
||||
if (cdns_power_is_lost(cdns)) {
|
||||
phy_exit(cdns->usb2_phy);
|
||||
ret = phy_init(cdns->usb2_phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
phy_exit(cdns->usb3_phy);
|
||||
ret = phy_init(cdns->usb3_phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = set_phy_power_on(cdns);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -270,10 +283,18 @@ static int cdns3_plat_runtime_resume(struct device *dev)
|
|||
static int cdns3_plat_suspend(struct device *dev)
|
||||
{
|
||||
struct cdns *cdns = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
cdns_suspend(cdns);
|
||||
|
||||
return cdns3_controller_suspend(dev, PMSG_SUSPEND);
|
||||
ret = cdns3_controller_suspend(dev, PMSG_SUSPEND);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (device_may_wakeup(dev) && cdns->wakeup_irq)
|
||||
enable_irq_wake(cdns->wakeup_irq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdns3_plat_resume(struct device *dev)
|
||||
|
|
|
@ -214,7 +214,6 @@ DECLARE_EVENT_CLASS(cdns3_log_request,
|
|||
__field(int, no_interrupt)
|
||||
__field(int, start_trb)
|
||||
__field(int, end_trb)
|
||||
__field(struct cdns3_trb *, start_trb_addr)
|
||||
__field(int, flags)
|
||||
__field(unsigned int, stream_id)
|
||||
),
|
||||
|
@ -230,12 +229,11 @@ DECLARE_EVENT_CLASS(cdns3_log_request,
|
|||
__entry->no_interrupt = req->request.no_interrupt;
|
||||
__entry->start_trb = req->start_trb;
|
||||
__entry->end_trb = req->end_trb;
|
||||
__entry->start_trb_addr = req->trb;
|
||||
__entry->flags = req->flags;
|
||||
__entry->stream_id = req->request.stream_id;
|
||||
),
|
||||
TP_printk("%s: req: %p, req buff %p, length: %u/%u %s%s%s, status: %d,"
|
||||
" trb: [start:%d, end:%d: virt addr %pa], flags:%x SID: %u",
|
||||
" trb: [start:%d, end:%d], flags:%x SID: %u",
|
||||
__get_str(name), __entry->req, __entry->buf, __entry->actual,
|
||||
__entry->length,
|
||||
__entry->zero ? "Z" : "z",
|
||||
|
@ -244,7 +242,6 @@ DECLARE_EVENT_CLASS(cdns3_log_request,
|
|||
__entry->status,
|
||||
__entry->start_trb,
|
||||
__entry->end_trb,
|
||||
__entry->start_trb_addr,
|
||||
__entry->flags,
|
||||
__entry->stream_id
|
||||
)
|
||||
|
|
|
@ -727,7 +727,7 @@ int cdnsp_reset_device(struct cdnsp_device *pdev)
|
|||
* are in Disabled state.
|
||||
*/
|
||||
for (i = 1; i < CDNSP_ENDPOINTS_NUM; ++i)
|
||||
pdev->eps[i].ep_state |= EP_STOPPED;
|
||||
pdev->eps[i].ep_state |= EP_STOPPED | EP_UNCONFIGURED;
|
||||
|
||||
trace_cdnsp_handle_cmd_reset_dev(slot_ctx);
|
||||
|
||||
|
@ -942,6 +942,7 @@ static int cdnsp_gadget_ep_enable(struct usb_ep *ep,
|
|||
|
||||
pep = to_cdnsp_ep(ep);
|
||||
pdev = pep->pdev;
|
||||
pep->ep_state &= ~EP_UNCONFIGURED;
|
||||
|
||||
if (dev_WARN_ONCE(pdev->dev, pep->ep_state & EP_ENABLED,
|
||||
"%s is already enabled\n", pep->name))
|
||||
|
@ -1023,9 +1024,13 @@ static int cdnsp_gadget_ep_disable(struct usb_ep *ep)
|
|||
goto finish;
|
||||
}
|
||||
|
||||
cdnsp_cmd_stop_ep(pdev, pep);
|
||||
pep->ep_state |= EP_DIS_IN_RROGRESS;
|
||||
cdnsp_cmd_flush_ep(pdev, pep);
|
||||
|
||||
/* Endpoint was unconfigured by Reset Device command. */
|
||||
if (!(pep->ep_state & EP_UNCONFIGURED)) {
|
||||
cdnsp_cmd_stop_ep(pdev, pep);
|
||||
cdnsp_cmd_flush_ep(pdev, pep);
|
||||
}
|
||||
|
||||
/* Remove all queued USB requests. */
|
||||
while (!list_empty(&pep->pending_list)) {
|
||||
|
@ -1043,10 +1048,12 @@ static int cdnsp_gadget_ep_disable(struct usb_ep *ep)
|
|||
|
||||
cdnsp_endpoint_zero(pdev, pep);
|
||||
|
||||
ret = cdnsp_update_eps_configuration(pdev, pep);
|
||||
if (!(pep->ep_state & EP_UNCONFIGURED))
|
||||
ret = cdnsp_update_eps_configuration(pdev, pep);
|
||||
|
||||
cdnsp_free_endpoint_rings(pdev, pep);
|
||||
|
||||
pep->ep_state &= ~EP_ENABLED;
|
||||
pep->ep_state &= ~(EP_ENABLED | EP_UNCONFIGURED);
|
||||
pep->ep_state |= EP_STOPPED;
|
||||
|
||||
finish:
|
||||
|
|
|
@ -835,6 +835,7 @@ struct cdnsp_ep {
|
|||
#define EP_WEDGE BIT(4)
|
||||
#define EP0_HALTED_STATUS BIT(5)
|
||||
#define EP_HAS_STREAMS BIT(6)
|
||||
#define EP_UNCONFIGURED BIT(7)
|
||||
|
||||
bool skip;
|
||||
};
|
||||
|
|
|
@ -686,7 +686,7 @@ static void cdnsp_free_priv_device(struct cdnsp_device *pdev)
|
|||
|
||||
static int cdnsp_alloc_priv_device(struct cdnsp_device *pdev)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
int ret;
|
||||
|
||||
ret = cdnsp_init_device_ctx(pdev);
|
||||
if (ret)
|
||||
|
@ -1231,7 +1231,6 @@ int cdnsp_mem_init(struct cdnsp_device *pdev)
|
|||
if (!pdev->dcbaa)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(pdev->dcbaa, 0, sizeof(*pdev->dcbaa));
|
||||
pdev->dcbaa->dma = dma;
|
||||
|
||||
cdnsp_write_64(dma, &pdev->op_regs->dcbaa_ptr);
|
||||
|
|
|
@ -525,9 +525,36 @@ EXPORT_SYMBOL_GPL(cdns_suspend);
|
|||
int cdns_resume(struct cdns *cdns, u8 set_active)
|
||||
{
|
||||
struct device *dev = cdns->dev;
|
||||
enum usb_role real_role;
|
||||
bool role_changed = false;
|
||||
int ret = 0;
|
||||
|
||||
if (cdns_power_is_lost(cdns)) {
|
||||
if (cdns->role_sw) {
|
||||
cdns->role = cdns_role_get(cdns->role_sw);
|
||||
} else {
|
||||
real_role = cdns_hw_role_state_machine(cdns);
|
||||
if (real_role != cdns->role) {
|
||||
ret = cdns_hw_role_switch(cdns);
|
||||
if (ret)
|
||||
return ret;
|
||||
role_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!role_changed) {
|
||||
if (cdns->role == USB_ROLE_HOST)
|
||||
ret = cdns_drd_host_on(cdns);
|
||||
else if (cdns->role == USB_ROLE_DEVICE)
|
||||
ret = cdns_drd_gadget_on(cdns);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (cdns->roles[cdns->role]->resume)
|
||||
cdns->roles[cdns->role]->resume(cdns, false);
|
||||
cdns->roles[cdns->role]->resume(cdns, cdns_power_is_lost(cdns));
|
||||
|
||||
if (set_active) {
|
||||
pm_runtime_disable(dev);
|
||||
|
|
|
@ -478,3 +478,18 @@ int cdns_drd_exit(struct cdns *cdns)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Indicate the cdns3 core was power lost before */
|
||||
bool cdns_power_is_lost(struct cdns *cdns)
|
||||
{
|
||||
if (cdns->version == CDNS3_CONTROLLER_V1) {
|
||||
if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0)))
|
||||
return true;
|
||||
} else {
|
||||
if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cdns_power_is_lost);
|
||||
|
|
|
@ -215,5 +215,5 @@ int cdns_drd_gadget_on(struct cdns *cdns);
|
|||
void cdns_drd_gadget_off(struct cdns *cdns);
|
||||
int cdns_drd_host_on(struct cdns *cdns);
|
||||
void cdns_drd_host_off(struct cdns *cdns);
|
||||
|
||||
bool cdns_power_is_lost(struct cdns *cdns);
|
||||
#endif /* __LINUX_CDNS3_DRD */
|
||||
|
|
Загрузка…
Ссылка в новой задаче