root/drivers/usb/dwc3/debug.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * debug.h - DesignWare USB3 DRD Controller Debug Header
 *
 * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com
 *
 * Authors: Felipe Balbi <balbi@ti.com>,
 *          Sebastian Andrzej Siewior <bigeasy@linutronix.de>
 */

#ifndef __DWC3_DEBUG_H
#define __DWC3_DEBUG_H

#include "core.h"

/**
 * dwc3_mode_string - returns mode name
 * @mode: GCTL.PrtCapDir value
 */
static inline const char *dwc3_mode_string(u32 mode)
{
        switch (mode) {
        case DWC3_GCTL_PRTCAP_HOST:
                return "host";
        case DWC3_GCTL_PRTCAP_DEVICE:
                return "device";
        case DWC3_GCTL_PRTCAP_OTG:
                return "otg";
        default:
                return "UNKNOWN";
        }
}

/**
 * dwc3_gadget_ep_cmd_string - returns endpoint command string
 * @cmd: command code
 */
static inline const char *
dwc3_gadget_ep_cmd_string(u8 cmd)
{
        switch (cmd) {
        case DWC3_DEPCMD_DEPSTARTCFG:
                return "Start New Configuration";
        case DWC3_DEPCMD_ENDTRANSFER:
                return "End Transfer";
        case DWC3_DEPCMD_UPDATETRANSFER:
                return "Update Transfer";
        case DWC3_DEPCMD_STARTTRANSFER:
                return "Start Transfer";
        case DWC3_DEPCMD_CLEARSTALL:
                return "Clear Stall";
        case DWC3_DEPCMD_SETSTALL:
                return "Set Stall";
        case DWC3_DEPCMD_GETEPSTATE:
                return "Get Endpoint State";
        case DWC3_DEPCMD_SETTRANSFRESOURCE:
                return "Set Endpoint Transfer Resource";
        case DWC3_DEPCMD_SETEPCONFIG:
                return "Set Endpoint Configuration";
        default:
                return "UNKNOWN command";
        }
}

/**
 * dwc3_gadget_generic_cmd_string - returns generic command string
 * @cmd: command code
 */
static inline const char *
dwc3_gadget_generic_cmd_string(u8 cmd)
{
        switch (cmd) {
        case DWC3_DGCMD_SET_LMP:
                return "Set LMP";
        case DWC3_DGCMD_SET_PERIODIC_PAR:
                return "Set Periodic Parameters";
        case DWC3_DGCMD_XMIT_FUNCTION:
                return "Transmit Function Wake Device Notification";
        case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:
                return "Set Scratchpad Buffer Array Address Lo";
        case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI:
                return "Set Scratchpad Buffer Array Address Hi";
        case DWC3_DGCMD_SELECTED_FIFO_FLUSH:
                return "Selected FIFO Flush";
        case DWC3_DGCMD_ALL_FIFO_FLUSH:
                return "All FIFO Flush";
        case DWC3_DGCMD_SET_ENDPOINT_NRDY:
                return "Set Endpoint NRDY";
        case DWC3_DGCMD_SET_ENDPOINT_PRIME:
                return "Set Endpoint Prime";
        case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
                return "Run SoC Bus Loopback Test";
        case DWC3_DGCMD_DEV_NOTIFICATION:
                return "Device Notification";
        default:
                return "UNKNOWN";
        }
}

/**
 * dwc3_gadget_link_string - returns link name
 * @link_state: link state code
 */
static inline const char *
dwc3_gadget_link_string(enum dwc3_link_state link_state)
{
        switch (link_state) {
        case DWC3_LINK_STATE_U0:
                return "U0";
        case DWC3_LINK_STATE_U1:
                return "U1";
        case DWC3_LINK_STATE_U2:
                return "U2";
        case DWC3_LINK_STATE_U3:
                return "U3";
        case DWC3_LINK_STATE_SS_DIS:
                return "SS.Disabled";
        case DWC3_LINK_STATE_RX_DET:
                return "RX.Detect";
        case DWC3_LINK_STATE_SS_INACT:
                return "SS.Inactive";
        case DWC3_LINK_STATE_POLL:
                return "Polling";
        case DWC3_LINK_STATE_RECOV:
                return "Recovery";
        case DWC3_LINK_STATE_HRESET:
                return "Hot Reset";
        case DWC3_LINK_STATE_CMPLY:
                return "Compliance";
        case DWC3_LINK_STATE_LPBK:
                return "Loopback";
        case DWC3_LINK_STATE_RESET:
                return "Reset";
        case DWC3_LINK_STATE_RESUME:
                return "Resume";
        default:
                return "UNKNOWN link state";
        }
}

/**
 * dwc3_gadget_hs_link_string - returns highspeed and below link name
 * @link_state: link state code
 */
static inline const char *
dwc3_gadget_hs_link_string(enum dwc3_link_state link_state)
{
        switch (link_state) {
        case DWC3_LINK_STATE_U0:
                return "On";
        case DWC3_LINK_STATE_U2:
                return "Sleep";
        case DWC3_LINK_STATE_U3:
                return "Suspend";
        case DWC3_LINK_STATE_SS_DIS:
                return "Disconnected";
        case DWC3_LINK_STATE_RX_DET:
                return "Early Suspend";
        case DWC3_LINK_STATE_RECOV:
                return "Recovery";
        case DWC3_LINK_STATE_RESET:
                return "Reset";
        case DWC3_LINK_STATE_RESUME:
                return "Resume";
        default:
                return "UNKNOWN link state";
        }
}

/**
 * dwc3_trb_type_string - returns TRB type as a string
 * @type: the type of the TRB
 */
static inline const char *dwc3_trb_type_string(unsigned int type)
{
        switch (type) {
        case DWC3_TRBCTL_NORMAL:
                return "normal";
        case DWC3_TRBCTL_CONTROL_SETUP:
                return "setup";
        case DWC3_TRBCTL_CONTROL_STATUS2:
                return "status2";
        case DWC3_TRBCTL_CONTROL_STATUS3:
                return "status3";
        case DWC3_TRBCTL_CONTROL_DATA:
                return "data";
        case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
                return "isoc-first";
        case DWC3_TRBCTL_ISOCHRONOUS:
                return "isoc";
        case DWC3_TRBCTL_LINK_TRB:
                return "link";
        default:
                return "UNKNOWN";
        }
}

static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
{
        switch (state) {
        case EP0_UNCONNECTED:
                return "Unconnected";
        case EP0_SETUP_PHASE:
                return "Setup Phase";
        case EP0_DATA_PHASE:
                return "Data Phase";
        case EP0_STATUS_PHASE:
                return "Status Phase";
        default:
                return "UNKNOWN";
        }
}

/**
 * dwc3_gadget_event_string - returns event name
 * @event: the event code
 */
static inline const char *dwc3_gadget_event_string(char *str, size_t size,
                const struct dwc3_event_devt *event)
{
        enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK;

        switch (event->type) {
        case DWC3_DEVICE_EVENT_DISCONNECT:
                snprintf(str, size, "Disconnect: [%s]",
                                dwc3_gadget_link_string(state));
                break;
        case DWC3_DEVICE_EVENT_RESET:
                snprintf(str, size, "Reset [%s]",
                                dwc3_gadget_link_string(state));
                break;
        case DWC3_DEVICE_EVENT_CONNECT_DONE:
                snprintf(str, size, "Connection Done [%s]",
                                dwc3_gadget_link_string(state));
                break;
        case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
                snprintf(str, size, "Link Change [%s]",
                                dwc3_gadget_link_string(state));
                break;
        case DWC3_DEVICE_EVENT_WAKEUP:
                snprintf(str, size, "WakeUp [%s]",
                                dwc3_gadget_link_string(state));
                break;
        case DWC3_DEVICE_EVENT_SUSPEND:
                snprintf(str, size, "Suspend [%s]",
                                dwc3_gadget_link_string(state));
                break;
        case DWC3_DEVICE_EVENT_SOF:
                snprintf(str, size, "Start-Of-Frame [%s]",
                                dwc3_gadget_link_string(state));
                break;
        case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
                snprintf(str, size, "Erratic Error [%s]",
                                dwc3_gadget_link_string(state));
                break;
        case DWC3_DEVICE_EVENT_CMD_CMPL:
                snprintf(str, size, "Command Complete [%s]",
                                dwc3_gadget_link_string(state));
                break;
        case DWC3_DEVICE_EVENT_OVERFLOW:
                snprintf(str, size, "Overflow [%s]",
                                dwc3_gadget_link_string(state));
                break;
        default:
                snprintf(str, size, "UNKNOWN");
        }

        return str;
}

/**
 * dwc3_ep_event_string - returns event name
 * @event: then event code
 */
static inline const char *dwc3_ep_event_string(char *str, size_t size,
                const struct dwc3_event_depevt *event, u32 ep0state)
{
        u8 epnum = event->endpoint_number;
        size_t len;
        int status;

        len = scnprintf(str, size, "ep%d%s: ", epnum >> 1,
                        (epnum & 1) ? "in" : "out");

        status = event->status;

        switch (event->endpoint_event) {
        case DWC3_DEPEVT_XFERCOMPLETE:
                len += scnprintf(str + len, size - len,
                                "Transfer Complete (%c%c%c)",
                                status & DEPEVT_STATUS_SHORT ? 'S' : 's',
                                status & DEPEVT_STATUS_IOC ? 'I' : 'i',
                                status & DEPEVT_STATUS_LST ? 'L' : 'l');

                if (epnum <= 1)
                        scnprintf(str + len, size - len, " [%s]",
                                        dwc3_ep0_state_string(ep0state));
                break;
        case DWC3_DEPEVT_XFERINPROGRESS:
                scnprintf(str + len, size - len,
                                "Transfer In Progress [%08x] (%c%c%c)",
                                event->parameters,
                                status & DEPEVT_STATUS_SHORT ? 'S' : 's',
                                status & DEPEVT_STATUS_IOC ? 'I' : 'i',
                                status & DEPEVT_STATUS_LST ? 'M' : 'm');
                break;
        case DWC3_DEPEVT_XFERNOTREADY:
                len += scnprintf(str + len, size - len,
                                "Transfer Not Ready [%08x]%s",
                                event->parameters,
                                status & DEPEVT_STATUS_TRANSFER_ACTIVE ?
                                " (Active)" : " (Not Active)");

                /* Control Endpoints */
                if (epnum <= 1) {
                        int phase = DEPEVT_STATUS_CONTROL_PHASE(event->status);

                        switch (phase) {
                        case DEPEVT_STATUS_CONTROL_DATA:
                                scnprintf(str + len, size - len,
                                                " [Data Phase]");
                                break;
                        case DEPEVT_STATUS_CONTROL_STATUS:
                                scnprintf(str + len, size - len,
                                                " [Status Phase]");
                        }
                }
                break;
        case DWC3_DEPEVT_RXTXFIFOEVT:
                scnprintf(str + len, size - len, "FIFO");
                break;
        case DWC3_DEPEVT_STREAMEVT:
                status = event->status;

                switch (status) {
                case DEPEVT_STREAMEVT_FOUND:
                        scnprintf(str + len, size - len, " Stream %d Found",
                                        event->parameters);
                        break;
                case DEPEVT_STREAMEVT_NOTFOUND:
                default:
                        scnprintf(str + len, size - len, " Stream Not Found");
                        break;
                }

                break;
        case DWC3_DEPEVT_EPCMDCMPLT:
                scnprintf(str + len, size - len, "Endpoint Command Complete");
                break;
        default:
                scnprintf(str + len, size - len, "UNKNOWN");
        }

        return str;
}

/**
 * dwc3_gadget_event_type_string - return event name
 * @event: the event code
 */
static inline const char *dwc3_gadget_event_type_string(u8 event)
{
        switch (event) {
        case DWC3_DEVICE_EVENT_DISCONNECT:
                return "Disconnect";
        case DWC3_DEVICE_EVENT_RESET:
                return "Reset";
        case DWC3_DEVICE_EVENT_CONNECT_DONE:
                return "Connect Done";
        case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
                return "Link Status Change";
        case DWC3_DEVICE_EVENT_WAKEUP:
                return "Wake-Up";
        case DWC3_DEVICE_EVENT_HIBER_REQ:
                return "Hibernation";
        case DWC3_DEVICE_EVENT_SUSPEND:
                return "Suspend";
        case DWC3_DEVICE_EVENT_SOF:
                return "Start of Frame";
        case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
                return "Erratic Error";
        case DWC3_DEVICE_EVENT_CMD_CMPL:
                return "Command Complete";
        case DWC3_DEVICE_EVENT_OVERFLOW:
                return "Overflow";
        default:
                return "UNKNOWN";
        }
}

static inline const char *dwc3_decode_event(char *str, size_t size, u32 event,
                u32 ep0state)
{
        union dwc3_event evt;

        memcpy(&evt, &event, sizeof(event));

        if (evt.type.is_devspec)
                return dwc3_gadget_event_string(str, size, &evt.devt);
        else
                return dwc3_ep_event_string(str, size, &evt.depevt, ep0state);
}

static inline const char *dwc3_ep_cmd_status_string(int status)
{
        switch (status) {
        case -ETIMEDOUT:
                return "Timed Out";
        case 0:
                return "Successful";
        case DEPEVT_TRANSFER_NO_RESOURCE:
                return "No Resource";
        case DEPEVT_TRANSFER_BUS_EXPIRY:
                return "Bus Expiry";
        default:
                return "UNKNOWN";
        }
}

static inline const char *dwc3_gadget_generic_cmd_status_string(int status)
{
        switch (status) {
        case -ETIMEDOUT:
                return "Timed Out";
        case 0:
                return "Successful";
        case 1:
                return "Error";
        default:
                return "UNKNOWN";
        }
}


#ifdef CONFIG_DEBUG_FS
extern void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep);
extern void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep);
extern void dwc3_debugfs_init(struct dwc3 *d);
extern void dwc3_debugfs_exit(struct dwc3 *d);
#else
static inline void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep)
{  }
static inline void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep)
{  }
static inline void dwc3_debugfs_init(struct dwc3 *d)
{  }
static inline void dwc3_debugfs_exit(struct dwc3 *d)
{  }
#endif
#endif /* __DWC3_DEBUG_H */