lkml.org 
[lkml]   [2018]   [Jul]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 06/31] usb: usbssp: added template functions used by upper layer.
    Date
    Patch adds some functionality for initialization process.
    It adds to driver usbssp_reset and usbssp_start function.

    Next elements added are objects usbssp_gadget_ep0_ops,
    usbssp_gadget_ep_ops and usbssp_gadget_ops. These objects
    constitute the interface used by gadget subsystem.
    At this moment functions related to these objects are empty
    and do nothing.

    This patch also implements usbssp_gadget_init_endpoint and
    usbssp_gadget_free_endpoint used during initialization.

    Signed-off-by: Pawel Laszczak <pawell@cadence.com>
    ---
    drivers/usb/usbssp/gadget-ext-caps.h | 3 +
    drivers/usb/usbssp/gadget-if.c | 269 ++++++++++++++++++++++++++-
    drivers/usb/usbssp/gadget.c | 84 ++++++++-
    3 files changed, 350 insertions(+), 6 deletions(-)

    diff --git a/drivers/usb/usbssp/gadget-ext-caps.h b/drivers/usb/usbssp/gadget-ext-caps.h
    index 2bf327046376..86c0ce331037 100644
    --- a/drivers/usb/usbssp/gadget-ext-caps.h
    +++ b/drivers/usb/usbssp/gadget-ext-caps.h
    @@ -51,3 +51,6 @@
    #define USBSSP_CMD_EWE BIT(10)

    #define USBSSP_IRQS (USBSSP_CMD_EIE | USBSSP_CMD_HSEIE | USBSSP_CMD_EWE)
    +
    +/* true: Controller Not Ready to accept doorbell or op reg writes after reset */
    +#define USBSSP_STS_CNR BIT(11)
    diff --git a/drivers/usb/usbssp/gadget-if.c b/drivers/usb/usbssp/gadget-if.c
    index d53e0fb65299..70def978b085 100644
    --- a/drivers/usb/usbssp/gadget-if.c
    +++ b/drivers/usb/usbssp/gadget-if.c
    @@ -12,13 +12,278 @@
    #include <linux/usb/composite.h>
    #include "gadget.h"

    +static int usbssp_gadget_ep_enable(struct usb_ep *ep,
    + const struct usb_endpoint_descriptor *desc)
    +{
    + struct usbssp_ep *ep_priv = to_usbssp_ep(ep);
    + int ret = 0;
    +
    + if (!ep_priv)
    + return -EINVAL;
    +
    + /*TODO: implements this function*/
    + return ret;
    +}
    +
    +int usbssp_gadget_ep_disable(struct usb_ep *ep)
    +{
    + struct usbssp_ep *ep_priv = to_usbssp_ep(ep);
    + int ret = 0;
    +
    + if (!ep_priv)
    + return -EINVAL;
    +
    + /*TODO: implements this function*/
    + return ret;
    +}
    +
    +static struct usb_request *usbssp_gadget_ep_alloc_request(struct usb_ep *ep,
    + gfp_t gfp_flags)
    +{
    + struct usbssp_ep *ep_priv = to_usbssp_ep(ep);
    +
    + if (!ep_priv)
    + return NULL;
    +
    + /*TODO: implements this function*/
    + return NULL;
    +}
    +
    +static void usbssp_gadget_ep_free_request(struct usb_ep *ep,
    + struct usb_request *request)
    +{
    + struct usbssp_ep *ep_priv = to_usbssp_ep(ep);
    +
    + if (!ep_priv)
    + return;
    +
    + /*TODO: implements this function*/
    +}
    +
    +static int usbssp_gadget_ep_queue(struct usb_ep *ep,
    + struct usb_request *request,
    + gfp_t gfp_flags)
    +{
    + struct usbssp_ep *ep_priv = to_usbssp_ep(ep);
    + int ret = 0;
    +
    + if (!ep_priv)
    + return -EINVAL;
    +
    + /*TODO: implements this function*/
    + return ret;
    +}
    +
    +static int usbssp_gadget_ep_dequeue(struct usb_ep *ep,
    + struct usb_request *request)
    +{
    + struct usbssp_ep *ep_priv = to_usbssp_ep(ep);
    + int ret = 0;
    +
    + if (!ep_priv)
    + return -EINVAL;
    +
    + /*TODO: implements this function*/
    + return ret;
    +}
    +
    +static int usbssp_gadget_ep_set_halt(struct usb_ep *ep, int value)
    +{
    + struct usbssp_ep *ep_priv = to_usbssp_ep(ep);
    + int ret = 0;
    +
    + if (!ep_priv)
    + return -EINVAL;
    +
    + /*TODO: implements this function*/
    + return ret;
    +}
    +
    +static int usbssp_gadget_ep_set_wedge(struct usb_ep *ep)
    +{
    + struct usbssp_ep *ep_priv = to_usbssp_ep(ep);
    + int ret = 0;
    +
    + if (!ep_priv)
    + return -EINVAL;
    +
    + /*TODO: implements this function*/
    + return ret;
    +}
    +
    +static const struct usb_ep_ops usbssp_gadget_ep0_ops = {
    + .enable = usbssp_gadget_ep_enable,
    + .disable = usbssp_gadget_ep_disable,
    + .alloc_request = usbssp_gadget_ep_alloc_request,
    + .free_request = usbssp_gadget_ep_free_request,
    + .queue = usbssp_gadget_ep_queue,
    + .dequeue = usbssp_gadget_ep_dequeue,
    + .set_halt = usbssp_gadget_ep_set_halt,
    + .set_wedge = usbssp_gadget_ep_set_wedge,
    +};
    +
    +static const struct usb_ep_ops usbssp_gadget_ep_ops = {
    + .enable = usbssp_gadget_ep_enable,
    + .disable = usbssp_gadget_ep_disable,
    + .alloc_request = usbssp_gadget_ep_alloc_request,
    + .free_request = usbssp_gadget_ep_free_request,
    + .queue = usbssp_gadget_ep_queue,
    + .dequeue = usbssp_gadget_ep_dequeue,
    + .set_halt = usbssp_gadget_ep_set_halt,
    + .set_wedge = usbssp_gadget_ep_set_wedge,
    +};
    +
    +static struct usb_endpoint_descriptor usbssp_gadget_ep0_desc = {
    + .bLength = USB_DT_ENDPOINT_SIZE,
    + .bDescriptorType = USB_DT_ENDPOINT,
    + .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
    +};
    +
    +static int usbssp_gadget_start(struct usb_gadget *g,
    + struct usb_gadget_driver *driver)
    +{
    + struct usbssp_udc *usbssp_data = gadget_to_usbssp(g);
    + int ret = 0;
    +
    + if (usbssp_data->gadget_driver) {
    + dev_err(usbssp_data->dev, "%s is already bound to %s\n",
    + usbssp_data->gadget.name,
    + usbssp_data->gadget_driver->driver.name);
    + ret = -EBUSY;
    + }
    +
    + /*TODO: add implementation*/
    + return ret;
    +}
    +
    +static int usbssp_gadget_stop(struct usb_gadget *g)
    +{
    + struct usbssp_udc *usbssp_data = gadget_to_usbssp(g);
    +
    + if (!usbssp_data)
    + return -EINVAL;
    + /*TODO: add implementation*/
    + return 0;
    +}
    +
    +static int usbssp_gadget_get_frame(struct usb_gadget *g)
    +{
    + struct usbssp_udc *usbssp_data = gadget_to_usbssp(g);
    +
    + if (!usbssp_data)
    + return -EINVAL;
    +
    + /*TODO: add implementation*/
    + return 0;
    +}
    +
    +static int usbssp_gadget_wakeup(struct usb_gadget *g)
    +{
    + struct usbssp_udc *usbssp_data = gadget_to_usbssp(g);
    +
    + if (!usbssp_data)
    + return -EINVAL;
    +
    + /*TODO: add implementation*/
    + return 0;
    +}
    +
    +static int usbssp_gadget_set_selfpowered(struct usb_gadget *g,
    + int is_selfpowered)
    +{
    + struct usbssp_udc *usbssp_data = gadget_to_usbssp(g);
    +
    + if (!usbssp_data)
    + return -EINVAL;
    +
    + /*TODO: add implementation*/
    + return 0;
    +}
    +
    +static const struct usb_gadget_ops usbssp_gadget_ops = {
    + .get_frame = usbssp_gadget_get_frame,
    + .wakeup = usbssp_gadget_wakeup,
    + .set_selfpowered = usbssp_gadget_set_selfpowered,
    + .udc_start = usbssp_gadget_start,
    + .udc_stop = usbssp_gadget_stop,
    +};
    +
    int usbssp_gadget_init_endpoint(struct usbssp_udc *usbssp_data)
    {
    - /*TODO: it has to be implemented*/
    + int i = 0;
    + struct usbssp_ep *ep_priv;
    +
    + usbssp_data->num_endpoints = USBSSP_ENDPOINTS_NUM;
    + INIT_LIST_HEAD(&usbssp_data->gadget.ep_list);
    +
    + for (i = 1; i < usbssp_data->num_endpoints; i++) {
    + bool direction = i & 1; /*start from OUT endpoint*/
    + u8 epnum = (i >> 1);
    +
    + ep_priv = &usbssp_data->devs.eps[i-1];
    + ep_priv->usbssp_data = usbssp_data;
    + ep_priv->number = epnum;
    + ep_priv->direction = direction; /*0 for OUT, 1 for IN*/
    +
    + snprintf(ep_priv->name, sizeof(ep_priv->name), "ep%d%s", epnum,
    + (ep_priv->direction) ? "in" : "out");
    +
    + ep_priv->endpoint.name = ep_priv->name;
    +
    + if (ep_priv->number < 2) {
    + ep_priv->endpoint.desc = &usbssp_gadget_ep0_desc;
    + ep_priv->endpoint.comp_desc = NULL;
    + }
    +
    + if (epnum == 0) {
    + /*EP0 is bidirectional endpoint*/
    + usb_ep_set_maxpacket_limit(&ep_priv->endpoint, 512);
    + dev_dbg(usbssp_data->dev,
    + "Initializing %s, MaxPack: %04x Type: Ctrl\n",
    + ep_priv->name, 512);
    + ep_priv->endpoint.maxburst = 1;
    + ep_priv->endpoint.ops = &usbssp_gadget_ep0_ops;
    + ep_priv->endpoint.caps.type_control = true;
    +
    + usbssp_data->usb_req_ep0_in.epnum = ep_priv->number;
    + usbssp_data->usb_req_ep0_in.dep = ep_priv;
    +
    + if (!epnum)
    + usbssp_data->gadget.ep0 = &ep_priv->endpoint;
    + } else {
    + usb_ep_set_maxpacket_limit(&ep_priv->endpoint, 1024);
    + ep_priv->endpoint.maxburst = 15;
    + ep_priv->endpoint.ops = &usbssp_gadget_ep_ops;
    + list_add_tail(&ep_priv->endpoint.ep_list,
    + &usbssp_data->gadget.ep_list);
    + ep_priv->endpoint.caps.type_iso = true;
    + ep_priv->endpoint.caps.type_bulk = true;
    + ep_priv->endpoint.caps.type_int = true;
    +
    + }
    +
    + ep_priv->endpoint.caps.dir_in = direction;
    + ep_priv->endpoint.caps.dir_out = !direction;
    +
    + dev_dbg(usbssp_data->dev, "Init %s, MaxPack: %04x SupType:"
    + " INT/BULK/ISOC , SupDir %s\n",
    + ep_priv->name, 1024,
    + (ep_priv->endpoint.caps.dir_in) ? "IN" : "OUT");
    +
    + INIT_LIST_HEAD(&ep_priv->pending_list);
    + }
    return 0;
    }

    void usbssp_gadget_free_endpoint(struct usbssp_udc *usbssp_data)
    {
    - /*TODO: it has to be implemented*/
    + int i;
    + struct usbssp_ep *ep_priv;
    +
    + for (i = 0; i < usbssp_data->num_endpoints; i++) {
    + ep_priv = &usbssp_data->devs.eps[i];
    +
    + if (ep_priv->number != 0)
    + list_del(&ep_priv->endpoint.ep_list);
    + }
    }
    diff --git a/drivers/usb/usbssp/gadget.c b/drivers/usb/usbssp/gadget.c
    index 338ec2ec18b1..195f5777cf8a 100644
    --- a/drivers/usb/usbssp/gadget.c
    +++ b/drivers/usb/usbssp/gadget.c
    @@ -103,6 +103,83 @@ int usbssp_halt(struct usbssp_udc *usbssp_data)
    return ret;
    }

    +/*
    + * Set the run bit and wait for the device to be running.
    + */
    +int usbssp_start(struct usbssp_udc *usbssp_data)
    +{
    + u32 temp;
    + int ret;
    +
    + temp = readl(&usbssp_data->op_regs->command);
    + temp |= (CMD_RUN | CMD_DEVEN);
    + usbssp_dbg_trace(usbssp_data, trace_usbssp_dbg_init,
    + "// Turn on USBSSP, cmd = 0x%x.", temp);
    + writel(temp, &usbssp_data->op_regs->command);
    +
    + /*
    + * Wait for the HCHalted Staus bit to be 0 to indicate the device is
    + * running.
    + */
    + ret = usbssp_handshake(&usbssp_data->op_regs->status,
    + STS_HALT, 0, USBSSP_MAX_HALT_USEC);
    +
    + if (ret == -ETIMEDOUT)
    + dev_err(usbssp_data->dev, "Device took too long to start, waited %u microseconds.\n",
    + USBSSP_MAX_HALT_USEC);
    + if (!ret)
    + /* clear state flags. Including dying, halted or removing */
    + usbssp_data->usbssp_state = 0;
    +
    + return ret;
    +}
    +
    +/*
    + * Reset a halted DC.
    + *
    + * This resets pipelines, timers, counters, state machines, etc.
    + * Transactions will be terminated immediately, and operational registers
    + * will be set to their defaults.
    + */
    +int usbssp_reset(struct usbssp_udc *usbssp_data)
    +{
    + u32 command;
    + u32 state;
    + int ret;
    +
    + state = readl(&usbssp_data->op_regs->status);
    +
    + if (state == ~(u32)0) {
    + dev_warn(usbssp_data->dev, "Device not accessible, reset failed.\n");
    + return -ENODEV;
    + }
    +
    + if ((state & STS_HALT) == 0) {
    + dev_warn(usbssp_data->dev, "DC not halted, aborting reset.\n");
    + return 0;
    + }
    +
    + usbssp_dbg_trace(usbssp_data, trace_usbssp_dbg_init, "// Reset the DC");
    + command = readl(&usbssp_data->op_regs->command);
    + command |= CMD_RESET;
    + writel(command, &usbssp_data->op_regs->command);
    +
    + ret = usbssp_handshake(&usbssp_data->op_regs->command,
    + CMD_RESET, 0, 10 * 1000 * 1000);
    +
    + if (ret)
    + return ret;
    + usbssp_dbg_trace(usbssp_data, trace_usbssp_dbg_init,
    + "Wait for controller to be ready for doorbell rings");
    + /*
    + * USBSSP cannot write to any doorbells or operational registers other
    + * than status until the "Controller Not Ready" flag is cleared.
    + */
    + ret = usbssp_handshake(&usbssp_data->op_regs->status,
    + STS_CNR, 0, 10 * 1000 * 1000);
    +
    + return ret;
    +}

    /*
    * Initialize memory for gadget driver and USBSSP (one-time init).
    @@ -179,8 +256,7 @@ int usbssp_gen_setup(struct usbssp_udc *usbssp_data)

    dev_dbg(usbssp_data->dev, "Resetting Device Controller\n");
    /* Reset the internal DC memory state and registers. */
    - /*TODO: add implementation of usbssp_reset function*/
    - //retval = usbssp_reset(usbssp_data);
    + retval = usbssp_reset(usbssp_data);
    if (retval)
    return retval;
    dev_dbg(usbssp_data->dev, "Reset complete\n");
    @@ -244,8 +320,7 @@ int usbssp_gadget_init(struct usbssp_udc *usbssp_data)
    BUILD_BUG_ON(sizeof(struct usbssp_run_regs) != (8+8*128)*32/8);

    /* fill gadget fields */
    - /*TODO: implements usbssp_gadget_ops object*/
    - //usbssp_data->gadget.ops = &usbssp_gadget_ops;
    + usbssp_data->gadget.ops = &usbssp_gadget_ops;
    usbssp_data->gadget.name = "usbssp-gadget";
    usbssp_data->gadget.max_speed = USB_SPEED_SUPER_PLUS;
    usbssp_data->gadget.speed = USB_SPEED_UNKNOWN;
    @@ -288,6 +363,7 @@ int usbssp_gadget_init(struct usbssp_udc *usbssp_data)
    usbssp_halt(usbssp_data);
    /*TODO add implementation of usbssp_reset function*/
    //usbssp_reset(usbssp_data);
    + usbssp_reset(usbssp_data);
    /*TODO add implementation of freeing memory*/
    //usbssp_mem_cleanup(usbssp_data);
    err3:
    --
    2.17.1
    \
     
     \ /
      Last update: 2018-07-19 20:01    [W:4.676 / U:0.080 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site