update(port): add ehci/ohci/dwc2 dcache support
Signed-off-by: sakumisu <1203593632@qq.com>
This commit is contained in:
@@ -17,11 +17,13 @@
|
|||||||
/* Enable print with color */
|
/* Enable print with color */
|
||||||
#define CONFIG_USB_PRINTF_COLOR_ENABLE
|
#define CONFIG_USB_PRINTF_COLOR_ENABLE
|
||||||
|
|
||||||
/* data align size when use dma */
|
/* data align size when use dma or use dcache */
|
||||||
#ifndef CONFIG_USB_ALIGN_SIZE
|
#ifndef CONFIG_USB_ALIGN_SIZE
|
||||||
#define CONFIG_USB_ALIGN_SIZE 4
|
#define CONFIG_USB_ALIGN_SIZE 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//#define CONFIG_USB_DCACHE_ENABLE
|
||||||
|
|
||||||
/* attribute data into no cache ram */
|
/* attribute data into no cache ram */
|
||||||
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
|
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
|
||||||
|
|
||||||
@@ -276,4 +278,18 @@
|
|||||||
/* ---------------- MUSB Configuration ---------------- */
|
/* ---------------- MUSB Configuration ---------------- */
|
||||||
// #define CONFIG_USB_MUSB_SUNXI
|
// #define CONFIG_USB_MUSB_SUNXI
|
||||||
|
|
||||||
|
/* ================ USB Dcache Configuration ==================*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||||
|
/* style 1*/
|
||||||
|
// void usb_dcache_clean(uintptr_t addr, uint32_t size);
|
||||||
|
// void usb_dcache_invalidate(uintptr_t addr, uint32_t size);
|
||||||
|
// void usb_dcache_flush(uintptr_t addr, uint32_t size);
|
||||||
|
|
||||||
|
/* style 2*/
|
||||||
|
// #define usb_dcache_clean(addr, size)
|
||||||
|
// #define usb_dcache_invalidate(addr, size)
|
||||||
|
// #define usb_dcache_flush(addr, size)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
19
common/usb_dcache.h
Normal file
19
common/usb_dcache.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, sakumisu
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#ifndef USB_DCACHE_H
|
||||||
|
#define USB_DCACHE_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||||
|
#if CONFIG_USB_ALIGN_SIZE % 32
|
||||||
|
#error "CONFIG_USB_ALIGN_SIZE must be multiple of 32"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define usb_dcache_clean(addr, size)
|
||||||
|
#define usb_dcache_invalidate(addr, size)
|
||||||
|
#define usb_dcache_flush(addr, size)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USB_DCACHE_H */
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "usb_osal.h"
|
#include "usb_osal.h"
|
||||||
#include "usbh_hub.h"
|
#include "usbh_hub.h"
|
||||||
#include "usb_memcpy.h"
|
#include "usb_memcpy.h"
|
||||||
|
#include "usb_dcache.h"
|
||||||
#include "usb_version.h"
|
#include "usb_version.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ struct dwc2_chan {
|
|||||||
uint32_t xferlen;
|
uint32_t xferlen;
|
||||||
uint8_t chidx;
|
uint8_t chidx;
|
||||||
bool inuse;
|
bool inuse;
|
||||||
|
bool dir_in;
|
||||||
usb_osal_sem_t waitsem;
|
usb_osal_sem_t waitsem;
|
||||||
struct usbh_urb *urb;
|
struct usbh_urb *urb;
|
||||||
uint32_t iso_frame_idx;
|
uint32_t iso_frame_idx;
|
||||||
@@ -260,12 +261,22 @@ static inline void dwc2_chan_transfer(struct usbh_bus *bus, uint8_t ch_num, uint
|
|||||||
{
|
{
|
||||||
__IO uint32_t tmpreg;
|
__IO uint32_t tmpreg;
|
||||||
uint8_t is_oddframe;
|
uint8_t is_oddframe;
|
||||||
|
struct dwc2_chan *chan;
|
||||||
|
|
||||||
|
chan = &g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[ch_num];
|
||||||
|
|
||||||
/* Initialize the HCTSIZn register */
|
/* Initialize the HCTSIZn register */
|
||||||
USB_OTG_HC(ch_num)->HCTSIZ = (size & USB_OTG_HCTSIZ_XFRSIZ) |
|
USB_OTG_HC(ch_num)->HCTSIZ = (size & USB_OTG_HCTSIZ_XFRSIZ) |
|
||||||
(((uint32_t)num_packets << 19) & USB_OTG_HCTSIZ_PKTCNT) |
|
(((uint32_t)num_packets << 19) & USB_OTG_HCTSIZ_PKTCNT) |
|
||||||
(((uint32_t)pid << 29) & USB_OTG_HCTSIZ_DPID);
|
(((uint32_t)pid << 29) & USB_OTG_HCTSIZ_DPID);
|
||||||
|
|
||||||
|
if (!(ep_addr & 0x80)) {
|
||||||
|
chan->dir_in = false;
|
||||||
|
usb_dcache_clean((uintptr_t)buf, USB_ALIGN_UP(size, CONFIG_USB_ALIGN_SIZE));
|
||||||
|
} else {
|
||||||
|
chan->dir_in = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* xfer_buff MUST be 32-bits aligned */
|
/* xfer_buff MUST be 32-bits aligned */
|
||||||
USB_OTG_HC(ch_num)->HCDMA = (uint32_t)buf;
|
USB_OTG_HC(ch_num)->HCDMA = (uint32_t)buf;
|
||||||
|
|
||||||
@@ -754,6 +765,13 @@ int usbh_submit_urb(struct usbh_urb *urb)
|
|||||||
return -USB_ERR_INVAL;
|
return -USB_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||||
|
if (((uintptr_t)urb->setup % CONFIG_USB_ALIGN_SIZE) || ((uintptr_t)urb->transfer_buffer % CONFIG_USB_ALIGN_SIZE)) {
|
||||||
|
USB_LOG_ERR("urb buffer is not align with %d\r\n", CONFIG_USB_ALIGN_SIZE);
|
||||||
|
while (1) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
bus = urb->hport->bus;
|
bus = urb->hport->bus;
|
||||||
|
|
||||||
if (!(USB_OTG_HPRT & USB_OTG_HPRT_PCSTS) || !urb->hport->connected) {
|
if (!(USB_OTG_HPRT & USB_OTG_HPRT_PCSTS) || !urb->hport->connected) {
|
||||||
@@ -919,6 +937,10 @@ static void dwc2_inchan_irq_handler(struct usbh_bus *bus, uint8_t ch_num)
|
|||||||
urb->data_toggle = 1;
|
urb->data_toggle = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan->dir_in) {
|
||||||
|
usb_dcache_invalidate((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(count, CONFIG_USB_ALIGN_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
|
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
|
||||||
if (chan->ep0_state == DWC2_EP0_STATE_INDATA) {
|
if (chan->ep0_state == DWC2_EP0_STATE_INDATA) {
|
||||||
chan->ep0_state = DWC2_EP0_STATE_OUTSTATUS;
|
chan->ep0_state = DWC2_EP0_STATE_OUTSTATUS;
|
||||||
|
|||||||
@@ -76,10 +76,36 @@ static void ehci_qh_free(struct usbh_bus *bus, struct ehci_qh_hw *qh)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||||
|
static inline void usb_ehci_qh_qtd_flush(struct ehci_qh_hw *qh)
|
||||||
|
{
|
||||||
|
struct ehci_qtd_hw *qtd;
|
||||||
|
|
||||||
|
qtd = EHCI_ADDR2QTD(qh->first_qtd);
|
||||||
|
|
||||||
|
while (qtd) {
|
||||||
|
usb_dcache_clean((uintptr_t)&qtd->hw, USB_ALIGN_UP(SIZEOF_EHCI_QTD, CONFIG_USB_EHCI_ALIGN_SIZE));
|
||||||
|
|
||||||
|
if (!qtd->dir_in) {
|
||||||
|
usb_dcache_clean(qtd->bufaddr, USB_ALIGN_UP(qtd->length, CONFIG_USB_ALIGN_SIZE));
|
||||||
|
}
|
||||||
|
qtd = EHCI_ADDR2QTD(qtd->hw.next_qtd);
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_dcache_clean((uintptr_t)&qh->hw, USB_ALIGN_UP(SIZEOF_EHCI_QH, CONFIG_USB_EHCI_ALIGN_SIZE));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define usb_ehci_qh_qtd_flush(qh)
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void ehci_qh_add_head(struct ehci_qh_hw *head, struct ehci_qh_hw *n)
|
static inline void ehci_qh_add_head(struct ehci_qh_hw *head, struct ehci_qh_hw *n)
|
||||||
{
|
{
|
||||||
n->hw.hlp = head->hw.hlp;
|
n->hw.hlp = head->hw.hlp;
|
||||||
|
usb_ehci_qh_qtd_flush(n);
|
||||||
|
|
||||||
head->hw.hlp = QH_HLP_QH(n);
|
head->hw.hlp = QH_HLP_QH(n);
|
||||||
|
|
||||||
|
usb_dcache_clean((uintptr_t)&head->hw, USB_ALIGN_UP(SIZEOF_EHCI_QH, CONFIG_USB_EHCI_ALIGN_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ehci_qh_remove(struct ehci_qh_hw *head, struct ehci_qh_hw *n)
|
static inline void ehci_qh_remove(struct ehci_qh_hw *head, struct ehci_qh_hw *n)
|
||||||
@@ -92,6 +118,7 @@ static inline void ehci_qh_remove(struct ehci_qh_hw *head, struct ehci_qh_hw *n)
|
|||||||
|
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
tmp->hw.hlp = n->hw.hlp;
|
tmp->hw.hlp = n->hw.hlp;
|
||||||
|
usb_dcache_clean((uintptr_t)&tmp->hw, USB_ALIGN_UP(SIZEOF_EHCI_QH, CONFIG_USB_EHCI_ALIGN_SIZE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,6 +282,8 @@ static void ehci_qtd_fill(struct ehci_qtd_hw *qtd, uint32_t bufaddr, size_t bufl
|
|||||||
qtd->hw.token = token;
|
qtd->hw.token = token;
|
||||||
|
|
||||||
ehci_qtd_bpl_fill(qtd, bufaddr, buflen);
|
ehci_qtd_bpl_fill(qtd, bufaddr, buflen);
|
||||||
|
qtd->dir_in = ((token & QTD_TOKEN_PID_MASK) == QTD_TOKEN_PID_IN) ? true : false;
|
||||||
|
qtd->bufaddr = bufaddr;
|
||||||
qtd->length = buflen;
|
qtd->length = buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,6 +620,9 @@ static void ehci_qh_scan_qtds(struct usbh_bus *bus, struct ehci_qh_hw *qhead, st
|
|||||||
qtd = EHCI_ADDR2QTD(qh->first_qtd);
|
qtd = EHCI_ADDR2QTD(qh->first_qtd);
|
||||||
|
|
||||||
while (qtd) {
|
while (qtd) {
|
||||||
|
if (qtd->dir_in) {
|
||||||
|
usb_dcache_invalidate(qtd->bufaddr, USB_ALIGN_UP(qtd->length - ((qtd->hw.token & QTD_TOKEN_NBYTES_MASK) >> QTD_TOKEN_NBYTES_SHIFT), CONFIG_USB_ALIGN_SIZE));
|
||||||
|
}
|
||||||
qtd->urb->actual_length += (qtd->length - ((qtd->hw.token & QTD_TOKEN_NBYTES_MASK) >> QTD_TOKEN_NBYTES_SHIFT));
|
qtd->urb->actual_length += (qtd->length - ((qtd->hw.token & QTD_TOKEN_NBYTES_MASK) >> QTD_TOKEN_NBYTES_SHIFT));
|
||||||
|
|
||||||
qh->first_qtd = qtd->hw.next_qtd;
|
qh->first_qtd = qtd->hw.next_qtd;
|
||||||
@@ -611,6 +643,7 @@ static void ehci_check_qh(struct usbh_bus *bus, struct ehci_qh_hw *qhead, struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (qtd) {
|
while (qtd) {
|
||||||
|
usb_dcache_invalidate((uintptr_t)&qtd->hw, USB_ALIGN_UP(SIZEOF_EHCI_QTD, CONFIG_USB_EHCI_ALIGN_SIZE));
|
||||||
token = qtd->hw.token;
|
token = qtd->hw.token;
|
||||||
|
|
||||||
if (token & QTD_TOKEN_STATUS_ERRORS) {
|
if (token & QTD_TOKEN_STATUS_ERRORS) {
|
||||||
@@ -766,6 +799,10 @@ int usb_hc_init(struct usbh_bus *bus)
|
|||||||
g_framelist[bus->hcd.hcd_id][i] = QH_HLP_QH(&g_periodic_qh_head[bus->hcd.hcd_id]);
|
g_framelist[bus->hcd.hcd_id][i] = QH_HLP_QH(&g_periodic_qh_head[bus->hcd.hcd_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usb_dcache_clean((uintptr_t)&g_async_qh_head[bus->hcd.hcd_id].hw, USB_ALIGN_UP(SIZEOF_EHCI_QH, CONFIG_USB_EHCI_ALIGN_SIZE));
|
||||||
|
usb_dcache_clean((uintptr_t)&g_periodic_qh_head[bus->hcd.hcd_id].hw, USB_ALIGN_UP(SIZEOF_EHCI_QH, CONFIG_USB_EHCI_ALIGN_SIZE));
|
||||||
|
usb_dcache_clean((uintptr_t)g_framelist[bus->hcd.hcd_id], sizeof(uint32_t) * CONFIG_USB_EHCI_FRAME_LIST_SIZE);
|
||||||
|
|
||||||
usb_hc_low_level_init(bus);
|
usb_hc_low_level_init(bus);
|
||||||
|
|
||||||
USB_LOG_INFO("EHCI HCIVERSION:0x%04x\r\n", (unsigned int)EHCI_HCCR->hciversion);
|
USB_LOG_INFO("EHCI HCIVERSION:0x%04x\r\n", (unsigned int)EHCI_HCCR->hciversion);
|
||||||
@@ -1138,6 +1175,13 @@ int usbh_submit_urb(struct usbh_urb *urb)
|
|||||||
return -USB_ERR_INVAL;
|
return -USB_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_DCACHE_ENABLE
|
||||||
|
if (((uintptr_t)urb->setup % CONFIG_USB_ALIGN_SIZE) || ((uintptr_t)urb->transfer_buffer % CONFIG_USB_ALIGN_SIZE)) {
|
||||||
|
USB_LOG_ERR("urb buffer is not align with %d\r\n", CONFIG_USB_ALIGN_SIZE);
|
||||||
|
while (1) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
bus = urb->hport->bus;
|
bus = urb->hport->bus;
|
||||||
|
|
||||||
/* find active hubport in roothub */
|
/* find active hubport in roothub */
|
||||||
|
|||||||
@@ -30,14 +30,19 @@
|
|||||||
#ifndef CONFIG_USB_EHCI_ISO_NUM
|
#ifndef CONFIG_USB_EHCI_ISO_NUM
|
||||||
#define CONFIG_USB_EHCI_ISO_NUM 4
|
#define CONFIG_USB_EHCI_ISO_NUM 4
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef CONFIG_USB_EHCI_ALIGN_SIZE
|
||||||
|
#define CONFIG_USB_EHCI_ALIGN_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
extern uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port);
|
extern uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port);
|
||||||
|
|
||||||
struct ehci_qtd_hw {
|
struct ehci_qtd_hw {
|
||||||
struct ehci_qtd hw;
|
struct ehci_qtd hw;
|
||||||
struct usbh_urb *urb;
|
struct usbh_urb *urb;
|
||||||
|
bool dir_in;
|
||||||
|
uintptr_t bufaddr;
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
} __attribute__((aligned(32)));
|
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
|
||||||
|
|
||||||
struct ehci_qh_hw {
|
struct ehci_qh_hw {
|
||||||
struct ehci_qh hw;
|
struct ehci_qh hw;
|
||||||
@@ -46,7 +51,7 @@ struct ehci_qh_hw {
|
|||||||
struct usbh_urb *urb;
|
struct usbh_urb *urb;
|
||||||
usb_osal_sem_t waitsem;
|
usb_osal_sem_t waitsem;
|
||||||
uint8_t remove_in_iaad;
|
uint8_t remove_in_iaad;
|
||||||
} __attribute__((aligned(32)));
|
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
|
||||||
|
|
||||||
struct ehci_itd_hw {
|
struct ehci_itd_hw {
|
||||||
struct ehci_itd hw;
|
struct ehci_itd hw;
|
||||||
@@ -55,7 +60,8 @@ struct ehci_itd_hw {
|
|||||||
uint8_t mf_unmask;
|
uint8_t mf_unmask;
|
||||||
uint8_t mf_valid;
|
uint8_t mf_valid;
|
||||||
uint32_t pkt_idx[8];
|
uint32_t pkt_idx[8];
|
||||||
} __attribute__((aligned(32)));
|
bool dir_in;
|
||||||
|
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
|
||||||
|
|
||||||
struct ehci_iso_hw
|
struct ehci_iso_hw
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,14 +22,18 @@
|
|||||||
#ifndef CONFIG_USB_OHCI_TD_NUM
|
#ifndef CONFIG_USB_OHCI_TD_NUM
|
||||||
#define CONFIG_USB_OHCI_TD_NUM 3
|
#define CONFIG_USB_OHCI_TD_NUM 3
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef CONFIG_USB_OHCI_ALIGN_SIZE
|
||||||
|
#define CONFIG_USB_OHCI_ALIGN_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
struct ohci_ed_hw;
|
struct ohci_ed_hw;
|
||||||
struct ohci_td_hw {
|
struct ohci_td_hw {
|
||||||
struct ohci_gtd hw;
|
struct ohci_gtd hw;
|
||||||
struct usbh_urb *urb;
|
struct usbh_urb *urb;
|
||||||
|
bool dir_in;
|
||||||
uint32_t buf_start;
|
uint32_t buf_start;
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
} __attribute__((aligned(32))); /* min is 16bytes, we use 32 for cacheline */
|
} __attribute__((aligned(CONFIG_USB_OHCI_ALIGN_SIZE))); /* min is 16bytes, we use CONFIG_USB_OHCI_ALIGN_SIZE for cacheline */
|
||||||
|
|
||||||
struct ohci_ed_hw {
|
struct ohci_ed_hw {
|
||||||
struct ohci_ed hw;
|
struct ohci_ed hw;
|
||||||
@@ -37,7 +41,7 @@ struct ohci_ed_hw {
|
|||||||
uint32_t td_count;
|
uint32_t td_count;
|
||||||
uint8_t ed_type;
|
uint8_t ed_type;
|
||||||
usb_osal_sem_t waitsem;
|
usb_osal_sem_t waitsem;
|
||||||
} __attribute__((aligned(32))); /* min is 16bytes, we use 32 for cacheline */
|
} __attribute__((aligned(CONFIG_USB_OHCI_ALIGN_SIZE))); /* min is 16bytes, we use CONFIG_USB_OHCI_ALIGN_SIZE for cacheline */
|
||||||
|
|
||||||
struct ohci_hcd {
|
struct ohci_hcd {
|
||||||
bool ohci_ed_used[CONFIG_USB_OHCI_ED_NUM];
|
bool ohci_ed_used[CONFIG_USB_OHCI_ED_NUM];
|
||||||
|
|||||||
Reference in New Issue
Block a user