| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* | |
| * Cadence USBHS-DEV Driver. | |
| * Debug header file. | |
| * | |
| * Copyright (C) 2023 Cadence. | |
| * | |
| * Author: Pawel Laszczak <pawell@cadence.com> | |
| */ | |
| #ifndef __LINUX_CDNS2_DEBUG | |
| #define __LINUX_CDNS2_DEBUG | |
| static inline const char *cdns2_decode_usb_irq(char *str, size_t size, | |
| u8 usb_irq, u8 ext_irq) | |
| { | |
| int ret; | |
| ret = scnprintf(str, size, "usbirq: 0x%02x - ", usb_irq); | |
| if (usb_irq & USBIRQ_SOF) | |
| ret += scnprintf(str + ret, size - ret, "SOF "); | |
| if (usb_irq & USBIRQ_SUTOK) | |
| ret += scnprintf(str + ret, size - ret, "SUTOK "); | |
| if (usb_irq & USBIRQ_SUDAV) | |
| ret += scnprintf(str + ret, size - ret, "SETUP "); | |
| if (usb_irq & USBIRQ_SUSPEND) | |
| ret += scnprintf(str + ret, size - ret, "Suspend "); | |
| if (usb_irq & USBIRQ_URESET) | |
| ret += scnprintf(str + ret, size - ret, "Reset "); | |
| if (usb_irq & USBIRQ_HSPEED) | |
| ret += scnprintf(str + ret, size - ret, "HS "); | |
| if (usb_irq & USBIRQ_LPM) | |
| ret += scnprintf(str + ret, size - ret, "LPM "); | |
| ret += scnprintf(str + ret, size - ret, ", EXT: 0x%02x - ", ext_irq); | |
| if (ext_irq & EXTIRQ_WAKEUP) | |
| ret += scnprintf(str + ret, size - ret, "Wakeup "); | |
| if (ext_irq & EXTIRQ_VBUSFAULT_FALL) | |
| ret += scnprintf(str + ret, size - ret, "VBUS_FALL "); | |
| if (ext_irq & EXTIRQ_VBUSFAULT_RISE) | |
| ret += scnprintf(str + ret, size - ret, "VBUS_RISE "); | |
| if (ret == size - 1) | |
| pr_info("CDNS2: buffer may be truncated.\n"); | |
| return str; | |
| } | |
| static inline const char *cdns2_decode_dma_irq(char *str, size_t size, | |
| u32 ep_ists, u32 ep_sts, | |
| const char *ep_name) | |
| { | |
| int ret; | |
| ret = scnprintf(str, size, "ISTS: %08x, %s: %08x ", | |
| ep_ists, ep_name, ep_sts); | |
| if (ep_sts & DMA_EP_STS_IOC) | |
| ret += scnprintf(str + ret, size - ret, "IOC "); | |
| if (ep_sts & DMA_EP_STS_ISP) | |
| ret += scnprintf(str + ret, size - ret, "ISP "); | |
| if (ep_sts & DMA_EP_STS_DESCMIS) | |
| ret += scnprintf(str + ret, size - ret, "DESCMIS "); | |
| if (ep_sts & DMA_EP_STS_TRBERR) | |
| ret += scnprintf(str + ret, size - ret, "TRBERR "); | |
| if (ep_sts & DMA_EP_STS_OUTSMM) | |
| ret += scnprintf(str + ret, size - ret, "OUTSMM "); | |
| if (ep_sts & DMA_EP_STS_ISOERR) | |
| ret += scnprintf(str + ret, size - ret, "ISOERR "); | |
| if (ep_sts & DMA_EP_STS_DBUSY) | |
| ret += scnprintf(str + ret, size - ret, "DBUSY "); | |
| if (DMA_EP_STS_CCS(ep_sts)) | |
| ret += scnprintf(str + ret, size - ret, "CCS "); | |
| if (ret == size - 1) | |
| pr_info("CDNS2: buffer may be truncated.\n"); | |
| return str; | |
| } | |
| static inline const char *cdns2_decode_epx_irq(char *str, size_t size, | |
| char *ep_name, u32 ep_ists, | |
| u32 ep_sts) | |
| { | |
| return cdns2_decode_dma_irq(str, size, ep_ists, ep_sts, ep_name); | |
| } | |
| static inline const char *cdns2_decode_ep0_irq(char *str, size_t size, | |
| u32 ep_ists, u32 ep_sts, | |
| int dir) | |
| { | |
| return cdns2_decode_dma_irq(str, size, ep_ists, ep_sts, | |
| dir ? "ep0IN" : "ep0OUT"); | |
| } | |
| static inline const char *cdns2_raw_ring(struct cdns2_endpoint *pep, | |
| struct cdns2_trb *trbs, | |
| char *str, size_t size) | |
| { | |
| struct cdns2_ring *ring = &pep->ring; | |
| struct cdns2_trb *trb; | |
| dma_addr_t dma; | |
| int ret; | |
| int i; | |
| ret = scnprintf(str, size, "\n\t\tTR for %s:", pep->name); | |
| trb = &trbs[ring->dequeue]; | |
| dma = cdns2_trb_virt_to_dma(pep, trb); | |
| ret += scnprintf(str + ret, size - ret, | |
| "\n\t\tRing deq index: %d, trb: V=%p, P=0x%pad\n", | |
| ring->dequeue, trb, &dma); | |
| trb = &trbs[ring->enqueue]; | |
| dma = cdns2_trb_virt_to_dma(pep, trb); | |
| ret += scnprintf(str + ret, size - ret, | |
| "\t\tRing enq index: %d, trb: V=%p, P=0x%pad\n", | |
| ring->enqueue, trb, &dma); | |
| ret += scnprintf(str + ret, size - ret, | |
| "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", | |
| ring->free_trbs, ring->ccs, ring->pcs); | |
| if (TRBS_PER_SEGMENT > 40) { | |
| ret += scnprintf(str + ret, size - ret, | |
| "\t\tTransfer ring %d too big\n", TRBS_PER_SEGMENT); | |
| return str; | |
| } | |
| dma = ring->dma; | |
| for (i = 0; i < TRBS_PER_SEGMENT; ++i) { | |
| trb = &trbs[i]; | |
| ret += scnprintf(str + ret, size - ret, | |
| "\t\t@%pad %08x %08x %08x\n", &dma, | |
| le32_to_cpu(trb->buffer), | |
| le32_to_cpu(trb->length), | |
| le32_to_cpu(trb->control)); | |
| dma += sizeof(*trb); | |
| } | |
| if (ret == size - 1) | |
| pr_info("CDNS2: buffer may be truncated.\n"); | |
| return str; | |
| } | |
| static inline const char *cdns2_trb_type_string(u8 type) | |
| { | |
| switch (type) { | |
| case TRB_NORMAL: | |
| return "Normal"; | |
| case TRB_LINK: | |
| return "Link"; | |
| default: | |
| return "UNKNOWN"; | |
| } | |
| } | |
| static inline const char *cdns2_decode_trb(char *str, size_t size, u32 flags, | |
| u32 length, u32 buffer) | |
| { | |
| int type = TRB_FIELD_TO_TYPE(flags); | |
| int ret; | |
| switch (type) { | |
| case TRB_LINK: | |
| ret = scnprintf(str, size, | |
| "LINK %08x type '%s' flags %c:%c:%c%c:%c", | |
| buffer, cdns2_trb_type_string(type), | |
| flags & TRB_CYCLE ? 'C' : 'c', | |
| flags & TRB_TOGGLE ? 'T' : 't', | |
| flags & TRB_CHAIN ? 'C' : 'c', | |
| flags & TRB_CHAIN ? 'H' : 'h', | |
| flags & TRB_IOC ? 'I' : 'i'); | |
| break; | |
| case TRB_NORMAL: | |
| ret = scnprintf(str, size, | |
| "type: '%s', Buffer: %08x, length: %ld, burst len: %ld, " | |
| "flags %c:%c:%c%c:%c", | |
| cdns2_trb_type_string(type), | |
| buffer, TRB_LEN(length), | |
| TRB_FIELD_TO_BURST(length), | |
| flags & TRB_CYCLE ? 'C' : 'c', | |
| flags & TRB_ISP ? 'I' : 'i', | |
| flags & TRB_CHAIN ? 'C' : 'c', | |
| flags & TRB_CHAIN ? 'H' : 'h', | |
| flags & TRB_IOC ? 'I' : 'i'); | |
| break; | |
| default: | |
| ret = scnprintf(str, size, "type '%s' -> raw %08x %08x %08x", | |
| cdns2_trb_type_string(type), | |
| buffer, length, flags); | |
| } | |
| if (ret == size - 1) | |
| pr_info("CDNS2: buffer may be truncated.\n"); | |
| return str; | |
| } | |
| #endif /*__LINUX_CDNS2_DEBUG*/ |