ch569w-evt: add usbhs device mode driver (#6330)

ch569w-evt: add usbhs device mode driver

* usbd driver tested with cdc_vcom, internal loopback
  (can't run both MSH & usbd due to 16KB RAM limitation)
* reduce usrstack & main thread stack size for usbd test
* ch56x_uart.c : iron out UART0_PIN_ALT assignment
This commit is contained in:
emuzit 2022-08-24 19:59:37 +08:00 committed by GitHub
parent 9cfb864068
commit a38b39ac25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1493 additions and 184 deletions

View File

@ -12,6 +12,9 @@ if GetDepend('SOC_SERIES_CH569'):
if GetDepend('RT_USING_WDT'):
src += ['ch56x_wdt.c']
if GetDepend('RT_USING_USB_DEVICE'):
src += ['ch56x_usbd.c']
if GetDepend('RT_USING_PWM'):
src += ['ch56x_pwm.c']

View File

@ -45,8 +45,13 @@ static struct serial_device serial_device_0 =
{
.reg_base = (struct uart_registers *)UART0_REG_BASE,
.irqn = UART0_IRQn,
#ifndef BSP_USING_UART0_PIN_ALT
.rxd_pin = UART_RXD0_PIN,
.txd_pin = UART_TXD0_PIN,
#else
.rxd_pin = UART_RXD0_ALT,
.txd_pin = UART_TXD0_ALT,
#endif
.name = "uart0",
};
#endif
@ -250,22 +255,13 @@ int rt_hw_uart_init(void)
while (--n >= 0)
{
uint32_t flag, txd_pin, rxd_pin;
uint32_t flag;
struct serial_device *serial = devices[n];
serial->parent.ops = &uart_ops;
serial->parent.config = config;
txd_pin = serial->txd_pin;
rxd_pin = serial->rxd_pin;
#ifdef BSP_USING_UART0_PIN_ALT
if (serial->irqn == UART0_IRQn)
{
txd_pin = UART_TXD0_ALT;
rxd_pin = UART_RXD0_ALT;
}
#endif
rt_pin_mode(txd_pin, PIN_MODE_OUTPUT);
rt_pin_mode(rxd_pin, PIN_MODE_INPUT_PULLUP);
rt_pin_mode(serial->txd_pin, PIN_MODE_OUTPUT);
rt_pin_mode(serial->rxd_pin, PIN_MODE_INPUT_PULLUP);
sys_clk_off_by_irqn(serial->irqn, SYS_SLP_CLK_ON);

View File

@ -0,0 +1,574 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-08-22 Emuzit first version
*/
#include <rthw.h>
#include <rtdebug.h>
#include <drivers/usb_common.h>
#include <drivers/usb_device.h>
#include "ch56x_usbhs.h"
#include "ch56x_sys.h"
#include "isr_sp.h"
/*--------------------------------------------------------*/
/* Warning : Not fully tested, use at your own discretion */
/*--------------------------------------------------------*/
#ifdef SOC_SERIES_CH569
#define _attr_uepdma __attribute__((section(".dmadata"), aligned(16)))
#define _ep0_setup_dmabuf _dmadata_start
#else
#define _attr_uepdma __attribute__((aligned(4)))
#define _ep0_setup_dmabuf _dmadata_start
#define usbhs_irq_handler usb1_irq_handler
#define USBHS_IRQn USB1_IRQn
#define USBHS_REG_BASE USB1_REG_BASE
#define RAMX_BASE_ADDRESS RAMS_BASE_ADDRESS
#define UEP0_RT_DMA UEP_DMA[0]
#endif
#define UEP_MPS_64 64
#define UEP_MPS_512 512
#define _get_ep_idx(address) ((address) & USB_EPNO_MASK)
#define _get_ep_dir(address) ((address) & USB_DIR_MASK)
#define uep_dir_is_in(address) (_get_ep_dir(address) == USB_DIR_IN)
#define uep_dir_is_out(address) (_get_ep_dir(address) == USB_DIR_OUT)
extern uint32_t _dmadata_start[];
static uint32_t ep0_dmabuf[UEP_MPS_64 / 4] _attr_uepdma;
static uint32_t epx_dmabuf[UEP_ADDRESS_MAX][UEP_MPS_512 / 4] _attr_uepdma;
static struct ep_id usbhs_ep_pool[] =
{
{0x0, USB_EP_ATTR_CONTROL, USB_DIR_INOUT, 64, ID_ASSIGNED},
{0x1, USB_EP_ATTR_BULK, USB_DIR_IN, 512, ID_UNASSIGNED},
{0x1, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED},
{0x2, USB_EP_ATTR_INT, USB_DIR_IN, 512, ID_UNASSIGNED},
{0x2, USB_EP_ATTR_INT, USB_DIR_OUT, 512, ID_UNASSIGNED},
{0x3, USB_EP_ATTR_BULK, USB_DIR_IN, 512, ID_UNASSIGNED},
{0x3, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED},
#ifdef SOC_SERIES_CH569
/* FIXME: not sure how to deal with EP4, no UEP4_DMA register */
{0x4, USB_EP_ATTR_INT, USB_DIR_IN, 512, ID_UNASSIGNED},
{0x4, USB_EP_ATTR_INT, USB_DIR_OUT, 512, ID_UNASSIGNED},
{0x5, USB_EP_ATTR_BULK, USB_DIR_IN, 512, ID_UNASSIGNED},
{0x5, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED},
{0x6, USB_EP_ATTR_INT, USB_DIR_IN, 512, ID_UNASSIGNED},
{0x6, USB_EP_ATTR_INT, USB_DIR_OUT, 512, ID_UNASSIGNED},
{0x7, USB_EP_ATTR_BULK, USB_DIR_IN, 512, ID_UNASSIGNED},
{0x7, USB_EP_ATTR_BULK, USB_DIR_OUT, 512, ID_UNASSIGNED},
#endif
{0xff, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED},
};
static struct udcd udc_device;
static uint8_t setup_set_address;
static rt_err_t udc_set_address(uint8_t address)
{
/* DEV_AD should be updated after status stage IN token of SET_ADDRESS
* such that that IN token could still reach our device.
*/
setup_set_address = address | 0x80;
return RT_EOK;
}
static rt_err_t udc_set_config(uint8_t address)
{
return RT_EOK;
}
static rt_err_t udc_ep_set_stall(uint8_t address)
{
volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
uint8_t ep_idx = _get_ep_idx(address);
if (uep_dir_is_in(address))
usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask = UEP_RES_STALL;
else
usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask = UEP_RES_STALL;
return RT_EOK;
}
static rt_err_t udc_ep_clear_stall(uint8_t address)
{
volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
uint8_t ep_idx = _get_ep_idx(address);
if (uep_dir_is_in(address))
usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask = UEP_RES_NAK;
else
usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask = UEP_RES_NAK;
return RT_EOK;
}
static rt_err_t udc_ep_enable(struct uendpoint *ep)
{
volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
uint8_t ep_idx, address, mod;
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
address = EP_ADDRESS(ep);
ep_idx = _get_ep_idx(address);
if (ep_idx > 0 && ep_idx <= UEP_ADDRESS_MAX)
{
mod = uep_dir_is_in(address) ? RB_UEP_TX_EN : RB_UEP_RX_EN;
mod = _uep_mod_get(usbhs, ep_idx) | mod;
_uep_mod_set(usbhs, ep_idx, mod);
}
return RT_EOK;
}
static rt_err_t udc_ep_disable(struct uendpoint *ep)
{
volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
uint8_t ep_idx, address, mod;
RT_ASSERT(ep != RT_NULL);
RT_ASSERT(ep->ep_desc != RT_NULL);
address = EP_ADDRESS(ep);
ep_idx = _get_ep_idx(address);
if (ep_idx > 0 && ep_idx <= UEP_ADDRESS_MAX)
{
mod = uep_dir_is_in(address) ? RB_UEP_TX_EN : RB_UEP_RX_EN;
mod = _uep_mod_get(usbhs, ep_idx) & ~mod;
_uep_mod_set(usbhs, ep_idx, mod);
}
return RT_EOK;
}
static rt_size_t udc_ep_read_prepare(uint8_t address, void *buffer, rt_size_t size)
{
volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
uint8_t ep_idx = _get_ep_idx(address);
uint32_t dmabuf = (uint32_t)buffer;
if (uep_dir_is_in(address))
return 0;
if (size > (ep_idx ? UEP_MPS_512 : UEP_MPS_64))
size = (ep_idx ? UEP_MPS_512 : UEP_MPS_64);
/* need extra `buffer` copy if H/W requirement not met
* CH565/CH569 : DMA buffer resides in RAMX, 16-byte aligned
* CH567/CH568 : 4-byte aligned
*/
#ifdef SOC_SERIES_CH569
if (size > 0 && (dmabuf < RAMX_BASE_ADDRESS || (dmabuf & 0xf)))
{
dmabuf = (uint32_t)(ep_idx ? epx_dmabuf[ep_idx] : ep0_dmabuf);
}
/* Note : usbhs->UEP_RX_DMA[0] maps to usbhs->UEP0_RT_DMA actually */
usbhs->UEP_RX_DMA[ep_idx] = dmabuf & UEP_RT_DMA_MASK;
#else
if (size > 0 && (dmabuf & 3))
{
dmabuf = (uint32_t)(ep_idx ? epx_dmabuf[ep_idx] : ep0_dmabuf);
}
usbhs->UEP_DMA[ep_idx] = dmabuf & UEP_RT_DMA_MASK;
#endif
if (ep_idx == 0 && size == 0)
{
/* SETUP status stage, expect DATA1 */
usbhs->UEP_CTRL[0].RX_CTRL.reg = RB_UEP_RES_ACK | RB_UEP_TOG_DATA1;
}
else
{
/* keep TOG_MASK & AUTOTOG */
usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask = UEP_RES_ACK;
}
return size;
}
static rt_size_t udc_ep_read(uint8_t address, void *buffer)
{
volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
uint8_t ep_idx = _get_ep_idx(address);
uint32_t dmabuf;
rt_size_t size;
if (uep_dir_is_in(address))
return 0;
#ifdef SOC_SERIES_CH569
/* Note : usbhs->UEP_RX_DMA[0] maps to usbhs->UEP0_RT_DMA actually */
dmabuf = usbhs->UEP_RX_DMA[ep_idx] & UEP_RT_DMA_MASK;
#else
dmabuf = usbhs->UEP_DMA[ep_idx] & UEP_RT_DMA_MASK;
#endif
size = usbhs->RX_LEN;
/* copy if proxy buffer */
if (size > 0 && ((uint32_t)buffer & UEP_RT_DMA_MASK) != dmabuf)
{
dmabuf |= RAMX_BASE_ADDRESS;
rt_memcpy(buffer, (void *)dmabuf, size);
}
return size;
}
static rt_size_t udc_ep_write(uint8_t address, void *buffer, rt_size_t size)
{
volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
uint8_t ep_idx = _get_ep_idx(address);
uint32_t dmabuf = (uint32_t)buffer;
union _uh_rt_ctrl ctrl;
if (uep_dir_is_out(address))
return 0;
if (size > (ep_idx ? UEP_MPS_512 : UEP_MPS_64))
size = (ep_idx ? UEP_MPS_512 : UEP_MPS_64);
/* need extra `buffer` copy if H/W requirement not met
* CH565/CH569 : DMA buffer resides in RAMX, 16-byte aligned
* CH567/CH568 : 4-byte aligned
*/
#ifdef SOC_SERIES_CH569
if (size > 0 && (dmabuf < RAMX_BASE_ADDRESS || (dmabuf & 0xf)))
{
dmabuf = (uint32_t)(ep_idx ? epx_dmabuf[ep_idx] : ep0_dmabuf);
rt_memcpy((void *)dmabuf, buffer, size);
}
if (ep_idx == 0)
usbhs->UEP0_RT_DMA = dmabuf & UEP_RT_DMA_MASK;
else
usbhs->UEP_TX_DMA[ep_idx] = dmabuf & UEP_RT_DMA_MASK;
#else
if (size > 0 && (dmabuf & 3))
{
dmabuf = (uint32_t)(ep_idx ? epx_dmabuf[ep_idx] : ep0_dmabuf);
rt_memcpy((void *)dmabuf, buffer, size);
}
usbhs->UEP_DMA[ep_idx] = dmabuf & UEP_RT_DMA_MASK;
#endif
usbhs->UEP_CTRL[ep_idx].t_len = size;
/* keep TOG_MASK & AUTOTOG */
usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask = UEP_RES_ACK;
return size;
}
static rt_err_t udc_ep0_send_status(void)
{
volatile struct usbhs_registers *usbhs = (void *)USBHS_REG_BASE;
/* SETUP status stage : zero data length, always DATA1 */
usbhs->UEP_CTRL[0].t_len = 0;
/* This is the only case UEP0_RT_DMA is set to 0. */
usbhs->UEP0_RT_DMA = 0;
usbhs->UEP_CTRL[0].TX_CTRL.reg = RB_UEP_RES_ACK | RB_UEP_TOG_DATA1;
return RT_EOK;
}
static rt_err_t udc_suspend(void)
{
return RT_EOK;
}
static rt_err_t udc_wakeup(void)
{
return RT_EOK;
}
static const struct udcd_ops udcd_ops =
{
.set_address = udc_set_address,
.set_config = udc_set_config,
.ep_set_stall = udc_ep_set_stall,
.ep_clear_stall = udc_ep_clear_stall,
.ep_enable = udc_ep_enable,
.ep_disable = udc_ep_disable,
.ep_read_prepare = udc_ep_read_prepare,
.ep_read = udc_ep_read,
.ep_write = udc_ep_write,
.ep0_send_status = udc_ep0_send_status,
.suspend = udc_suspend,
.wakeup = udc_wakeup,
};
static void _hsbhs_device_mode_init(volatile struct usbhs_registers *usbhs)
{
uint8_t ep_idx;
/* disable all endpoints, use single buffer mode (BUF_MOD : 0) */
usbhs->UHOST_CTRL.reg = 0;
usbhs->SUSPEND.reg = 0;
usbhs->R32_UEP_MOD = 0;
usbhs->DEV_AD = 0;
usbhs->CTRL.reg = RB_USB_RESET_SIE | RB_USB_CLR_ALL;
usbhs->CTRL.reg = RB_USB_DEVICE_MODE |
RB_SPTP_HIGH_SPEED |
RB_DEV_PU_EN |
RB_USB_INT_BUSY |
RB_USB_DMA_EN;
usbhs->INT_EN.reg = RB_USB_IE_BUSRST |
RB_USB_IE_TRANS |
RB_USB_IE_FIFOOV |
RB_USB_IE_SETUPACT;
usbhs->UEP_MAX_LEN[0].reg = UEP_MPS_64;
/*
* It seems EP0 SETUP uses the first 8 bytes of RAMX as dmabuf and
* handles DATA0 transfer & ACK on its own. Here we still needs to
* RES_NAK TX/RX to block SETUP data stage till dma data is ready.
*/
usbhs->UEP_CTRL[0].TX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_TOG_DATA1;
usbhs->UEP_CTRL[0].RX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_TOG_DATA1;
for (ep_idx = 1; ep_idx <= UEP_ADDRESS_MAX; ep_idx++)
{
usbhs->UEP_MAX_LEN[ep_idx].reg = UEP_MPS_512;
/* set to DATA0, remains to be initialized (SET_CONFIGURATION...) */
usbhs->UEP_CTRL[ep_idx].TX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_AUTOTOG;
usbhs->UEP_CTRL[ep_idx].RX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_AUTOTOG;
}
}
static rt_err_t udc_device_init(struct rt_device *device)
{
volatile struct usbhs_registers *usbhs = device->user_data;
sys_clk_off_by_irqn(USBHS_IRQn, SYS_SLP_CLK_ON);
_hsbhs_device_mode_init(usbhs);
rt_hw_interrupt_umask(USBHS_IRQn);
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
static struct rt_device_ops device_ops;
#endif
static int rt_hw_usbd_init(void)
{
int ret;
udc_device.parent.type = RT_Device_Class_USBDevice;
#ifdef RT_USING_DEVICE_OPS
device_ops.init = udc_device_init;
udc_device.parent.ops = &device_ops;
#else
udc_device.parent.init = udc_device_init;
#endif
udc_device.parent.user_data = (void *)USBHS_REG_BASE;
udc_device.ops = &udcd_ops;
udc_device.ep_pool = usbhs_ep_pool;
udc_device.ep0.id = &usbhs_ep_pool[0];
udc_device.device_is_hs = RT_TRUE;
ret = rt_device_register(&udc_device.parent, "usbd", 0);
if (ret == RT_EOK)
ret = rt_usb_device_init();
return ret;
}
INIT_DEVICE_EXPORT(rt_hw_usbd_init);
rt_inline uint8_t _uep_tog_datax(uint8_t tog)
{
/* Note: treat tog as RB_UEP_TOG_DATA0 if not RB_UEP_TOG_DATA1 */
return (tog == RB_UEP_TOG_DATA1) ? RB_UEP_TOG_DATA0 : RB_UEP_TOG_DATA1;
}
static void _isr_ep_stall(volatile struct usbhs_registers *usbhs)
{
uint8_t ep_idx = usbhs->INT_ST.dev_endp_mask;
usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask == UEP_RES_STALL;
usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask == UEP_RES_STALL;
}
static void _isr_handle_setup(volatile struct usbhs_registers *usbhs)
{
struct urequest setup, *packet;
uint8_t ep_idx, xctrl, recipient;
/* RES_NAK to block data stage, will expect or response DATA1 */
usbhs->UEP_CTRL[0].TX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_TOG_DATA1;
usbhs->UEP_CTRL[0].RX_CTRL.reg = RB_UEP_RES_NAK | RB_UEP_TOG_DATA1;
packet = (struct urequest *)_ep0_setup_dmabuf;
setup.request_type = packet->request_type;
setup.bRequest = packet->bRequest;
setup.wValue = packet->wValue;
setup.wIndex = packet->wIndex;
setup.wLength = packet->wLength;
/* Init data toggle bit. Not sure if it has been done by h/w.*/
xctrl = RB_UEP_RES_NAK | RB_UEP_AUTOTOG | RB_UEP_TOG_DATA0;
recipient = setup.request_type & USB_REQ_TYPE_RECIPIENT_MASK;
if (recipient == USB_REQ_TYPE_DEVICE &&
setup.bRequest == USB_REQ_SET_CONFIGURATION)
{
for (ep_idx = 1; ep_idx <= UEP_ADDRESS_MAX; ep_idx++)
{
usbhs->UEP_CTRL[ep_idx].TX_CTRL.reg = xctrl;
usbhs->UEP_CTRL[ep_idx].RX_CTRL.reg = xctrl;
}
}
else if (recipient == USB_REQ_TYPE_ENDPOINT &&
setup.bRequest == USB_REQ_CLEAR_FEATURE &&
setup.wValue == USB_EP_HALT)
{
ep_idx = setup.wIndex;
if (ep_idx > 0 && ep_idx <= UEP_ADDRESS_MAX)
{
usbhs->UEP_CTRL[ep_idx].TX_CTRL.reg = xctrl;
usbhs->UEP_CTRL[ep_idx].RX_CTRL.reg = xctrl;
}
}
rt_usbd_ep0_setup_handler(&udc_device, &setup);
}
static void _isr_handle_transfer(volatile struct usbhs_registers *usbhs)
{
rt_size_t size;
uint8_t ep_idx, token, tog;
ep_idx = usbhs->INT_ST.dev_endp_mask;
token = usbhs->INT_ST.dev_token_mask;
if (ep_idx == 0)
{
if (token == DEV_TOKEN_IN)
{
/* UEP0 does not support AUTOTOG, generate DATAx manually */
tog = usbhs->UEP_CTRL[0].TX_CTRL.reg & RB_UEP_TOG_MASK;
tog = _uep_tog_datax(tog);
/* wait for udc_ep_write or udc_ep0_send_status to RES_ACK */
usbhs->UEP_CTRL[0].TX_CTRL.reg = RB_UEP_RES_NAK | tog;
if (setup_set_address != 0 && usbhs->UEP_CTRL[0].t_len == 0)
{
usbhs->DEV_AD = setup_set_address & 0x7f;
setup_set_address = 0;
}
/* don't call in_handler if send_status */
if (usbhs->UEP0_RT_DMA != 0)
{
rt_usbd_ep0_in_handler(&udc_device);
}
}
else if (token == DEV_TOKEN_OUT)
{
if (usbhs->INT_ST.st_togok)
{
/* UEP0 does not support AUTOTOG, generate DATAx manually */
tog = usbhs->UEP_CTRL[0].RX_CTRL.reg & RB_UEP_TOG_MASK;
tog = _uep_tog_datax(tog);
/* wait for udc_ep_read_prepare to RES_ACK */
usbhs->UEP_CTRL[0].RX_CTRL.reg = RB_UEP_RES_NAK | tog;
rt_usbd_ep0_out_handler(&udc_device, usbhs->RX_LEN);
}
else
{
/* Corrupted ACK Handshake => ignore data, keep sequence bit */
usbhs->UEP_CTRL[0].RX_CTRL.res_mask = UEP_RES_NAK;
}
}
}
else if (token == DEV_TOKEN_IN)
{
/* wait for udc_ep_write to RES_ACK */
usbhs->UEP_CTRL[ep_idx].TX_CTRL.res_mask = UEP_RES_NAK;
size = usbhs->UEP_CTRL[ep_idx].t_len;
rt_usbd_ep_in_handler(&udc_device, ep_idx | USB_DIR_IN, size);
}
else if (token == DEV_TOKEN_OUT)
{
/* wait for udc_ep_read_prepare to RES_ACK */
usbhs->UEP_CTRL[ep_idx].RX_CTRL.res_mask = UEP_RES_NAK;
/* ignore data if Corrupted ACK Handshake */
if (usbhs->INT_ST.st_togok)
{
/* size:0 to trigger dcd_ep_read() in _data_notify() */
rt_usbd_ep_out_handler(&udc_device, ep_idx | USB_DIR_OUT, 0);
}
}
}
/*
* CAVEAT: The usbd design of ch56x relies on instant isr to RES_NAK
* UEP_CTRL[n].TX_CTRL/RX_CTRL. A long tarried isr may leave RES_ACK
* in UEP_CTRL[n] and starts unintended DMA upon arrival of IN/OUT.
*/
void usbhs_irq_handler(void) __attribute__((interrupt()));
void usbhs_irq_handler(void)
{
volatile struct usbhs_registers *usbhs;
union _usb_int_fg intflag;
isr_sp_enter();
rt_interrupt_enter();
usbhs = (struct usbhs_registers *)USBHS_REG_BASE;
intflag.reg = usbhs->INT_FG.reg;
if (intflag.fifoov)
{
/* FIXME: fifo overflow */
_isr_ep_stall(usbhs);
}
else
{
if (intflag.transfer)
_isr_handle_transfer(usbhs);
if (intflag.setupact)
_isr_handle_setup(usbhs);
}
if (intflag.busrst)
{
_hsbhs_device_mode_init(usbhs);
rt_usbd_reset_handler(&udc_device);
}
/* clear all pending intflag (suspend, isoact & nak ignored) */
usbhs->INT_FG.reg = intflag.reg;
rt_interrupt_leave();
isr_sp_leave();
}

View File

@ -0,0 +1,679 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-08-22 Emuzit first version
*/
#ifndef __CH56X_USBHS_H__
#define __CH56X_USBHS_H__
#include "soc.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef SOC_SERIES_CH569
#define UEP_ADDRESS_MAX 7
#define UEP_RT_DMA_MASK 0x1fff0
#else
#define UEP_ADDRESS_MAX 4
#define UEP_RT_DMA_MASK 0x0fffc
#endif
union _usb_ctrl
{
uint8_t reg;
struct
{
uint8_t dma_en : 1; // RW, USB DMA and DMA interrupt enable bit
uint8_t clr_all : 1; // RW, Empty USB interrupt flag and FIFO
uint8_t reset_sie : 1; // RW, Forcibly reset the USB SIE
uint8_t int_busy : 1; // RW, Auto pause enable bit @ RB_USB_IF_TRANSFER
uint8_t pu_en : 1; // RW, device & pull-up-R enable, DEVICE mode
uint8_t sptp_mask : 2; // RW, USB bus signal transfer rate selection bit
uint8_t mode : 1; // RW, USB working mode selection bit
};
};
#define RB_USB_DMA_EN 0x01
#define RB_USB_CLR_ALL 0x02
#define RB_USB_RESET_SIE 0x04
#define RB_USB_INT_BUSY 0x08
#define RB_DEV_PU_EN 0x10
#define RB_USB_SPTP_MASK 0x60
#define RB_USB_MODE 0x80
#define USBHS_FULL_SPEED 0
#define USBHS_HIGH_SPEED 1
#define USBHS_LOW_SPEED 2
#define USBHS_DEVICE_MODE 0
#define USBHS_HOST_MODE 1
#define RB_SPTP_FULL_SPEED (USBHS_FULL_SPEED << 5)
#define RB_SPTP_HIGH_SPEED (USBHS_HIGH_SPEED << 5)
#define RB_SPTP_LOW_SPEED (USBHS_LOW_SPEED << 5)
#define RB_USB_DEVICE_MODE (USBHS_DEVICE_MODE << 7)
#define RB_USB_HOST_MODE (USBHS_HOST_MODE << 7)
union _usb_int_en
{
uint8_t reg;
struct
{
uint8_t busrst : 1; // RW, USB bus reset event IE, DEVICE mode
uint8_t trans : 1; // RW, USB transfer complete interrupt enable
uint8_t suspend : 1; // RW, USB bus suspend/wake-up event IE
uint8_t sof : 1; // RW, SOF packet/timing interrupt enable
uint8_t fifoov : 1; // RW, Internal FIFO overflow interrupt enable
#ifdef SOC_SERIES_CH569
uint8_t setupact : 1; // RW, SETUP transaction complete interrupt
uint8_t isoact : 1; // RW, ISOchronous token received IE
uint8_t dev_nak : 1; // RW, NAK interrupt enable, DEVICE mode
#else
uint8_t resv_5 : 1;
uint8_t dev_nak : 1; // RW, NAK interrupt enable, DEVICE mode
uint8_t dev_sof : 1; // RW, SOF packet received IE, DEVICE mode
#endif
};
struct
{
uint8_t detect : 1; // RW, USB device connect/disconnect IE, HOST mode
uint8_t stuff_1 : 7;
};
};
#define RB_USB_IE_BUSRST 0x01
#define RB_USB_IE_DETECT 0x01
#define RB_USB_IE_TRANS 0x02
#define RB_USB_IE_SUSPEND 0x04
#define RB_USB_IE_SOF 0x08
#define RB_USB_IE_FIFOOV 0x10
#ifdef SOC_SERIES_CH569
#define RB_USB_IE_SETUPACT 0x20
#define RB_USB_IE_ISOACT 0x40
#define RB_USB_IE_DEV_NAK 0x80
#else
#define RB_USB_IE_DEV_NAK 0x40
#define RB_USB_IE_DEV_SOF 0x80
#endif
union _usb_suspend
{
uint8_t reg;
struct
{
uint8_t resv_0 : 1;
uint8_t dev_wakeup : 1; // RW, Remote wake-up control bit
uint8_t resv_2 : 6;
};
};
#define RB_DEV_WAKEUP 0x02
union _usb_spd_type
{
uint8_t reg;
struct
{
uint8_t speed_mask : 2; // RO, Actual transfer speed
uint8_t resv_2 : 6;
};
};
#define RB_USBSPEED_MASK 0x03 // same USBHS_FULL_SPEED...
union _usb_mis_st
{
uint8_t reg;
struct
{
uint8_t split_en : 1; // RO, SPLIT packet transmission enabled, HOST mode
uint8_t attach : 1; // RO, USB device connection status bit, HOST mode
uint8_t bus_suspend : 1; // RO, USB suspend status bit
uint8_t bus_reset : 1; // RO, USB bus reset status bit
uint8_t fifo_rdy : 1; // RO, USB receive FIFO data ready status bit
uint8_t sie_free : 1; // RO, Free status bit of USB protocol processor
uint8_t sof_act : 1; // RO, SOF packet transfer status bit, HOST mode
uint8_t sof_pres : 1; // RO, SOF packet presage status bit, HOST mode
};
};
#define RB_HOST_SPLIT_EN 0x01
#define RB_USB_ATTACH 0x02
#define RB_USBBUS_SUSPEND 0x04
#define RB_USBBUS_RESET 0x08
#define RB_USB_FIFO_RDY 0x10
#define RB_USB_SIE_FREE 0x20
#define RB_USB_SOF_ACT 0x40
#define RB_USB_SOF_PRES 0x80
union _usb_int_fg
{
uint8_t reg;
struct
{
uint8_t busrst : 1; // RW1, USB bus reset event IF, DEVICE mode
uint8_t transfer : 1; // RW1, USB transmission complete interrupt flag
uint8_t suspend : 1; // RW1, USB bus suspend/wake-up event IF
uint8_t hst_sof : 1; // RW1, SOF timing interrupt flag bit, HOST mode
uint8_t fifoov : 1; // RW1, USB FIFO overflow interrupt flag
uint8_t setupact : 1; // RW1, SETUP transaction complete IF (CH569)
uint8_t isoact : 1; // RW1, ISOchronous token received IF (CH569)
uint8_t resv_7 : 1;
};
struct
{
uint8_t detect : 1; // RW1, USB device connect/disconnect IF, HOST mode
uint8_t stuff_1 : 7;
};
};
#define RB_USB_IF_BUSRST 0x01
#define RB_USB_IF_DETECT 0x01
#define RB_USB_IF_TRANSFER 0x02
#define RB_USB_IF_SUSPEND 0x04
#define RB_USB_IF_HST_SOF 0x08
#define RB_USB_IF_FIFOOV 0x10
#define RB_USB_IF_SETUPACT 0x20
#define RB_USB_IF_ISOACT 0x40
union _usb_int_st
{
uint8_t reg;
struct
{
uint8_t host_res_mask : 4; // RO, Current response PID, HOST mode
uint8_t dev_token_mask : 2; // RO, Current token PID, DEVICE mode
uint8_t st_togok : 1; // RO, Current transmit DATA0/1 sync state
uint8_t st_nak : 1; // RO, NAK response status bit, DEVICE mode
};
struct
{
uint8_t dev_endp_mask : 4; // RO, Current endpoint number, DEVICE mode
uint8_t stuff_4 : 4;
};
};
#define RB_HOST_RES_MASK 0x0f
#define RB_DEV_ENDP_MASK 0x0f
#define RB_DEV_TOKEN_MASK 0x30
#define RB_USB_ST_TOGOK 0x40
#define RB_USB_ST_NAK 0x80
#define DEV_TOKEN_OUT 0
#define DEV_TOKEN_SOF 1
#define DEV_TOKEN_IN 2
#define DEV_TOKEN_SETUP 3 // CH567/CH568
#define RB_DEV_TOKEN_OUT (DEV_TOKEN_OUT << 4)
#define RB_DEV_TOKEN_SOF (DEV_TOKEN_SOF << 4)
#define RB_DEV_TOKEN_IN (DEV_TOKEN_IN << 4)
/*
* RB_UEPn_ RB_UEPn_ RB_UEPn_ R32_UEPn_DMA as starting address, low to high
* RX_EN TX_EN BUF_MOD
* 0 0 x Endpoint is disabled, UEPn_DMA not used
* 1 0 0 1st address of RX (OUT) buffer is R32_UEPn_RX_DMA
* 1 0 1 RB_UEP_R_TOG_MASK=0, use R32_UEPn_RX_DMA
* RB_UEP_R_TOG_MASK=1, use R32_UEPn_TX_DMA
* 0 1 0 1st address of TX (IN) buffer is R32_UEPn_TX_DMA
* 0 1 1 RB_UEP_T_TOG_MASK=0, use R32_UEPn_TX_DMA
* RB_UEP_T_TOG_MASK=1, use R32_UEPn_RX_DMA
*/
#define RB_UEP_BUF_MOD 0x01
#define RB_UEP_TX_EN 0x04
#define RB_UEP_RX_EN 0x08
/* UEP_MOD offset 0 */
#define RB_UEP4_BUF_MOD 0x01
#define RB_UEP4_TX_EN 0x04
#define RB_UEP4_RX_EN 0x08
#define RB_UEP1_BUF_MOD 0x10
#define RB_UEP1_TX_EN 0x40
#define RB_UEP1_RX_EN 0x80
/* UEP_MOD offset 1 */
#define RB_UEP2_BUF_MOD 0x01
#define RB_UEP2_TX_EN 0x04
#define RB_UEP2_RX_EN 0x08
#define RB_UEP3_BUF_MOD 0x10
#define RB_UEP3_TX_EN 0x40
#define RB_UEP3_RX_EN 0x80
/* UEP_MOD offset 2 */
#define RB_UEP5_BUF_MOD 0x01
#define RB_UEP5_TX_EN 0x04
#define RB_UEP5_RX_EN 0x08
#define RB_UEP6_BUF_MOD 0x10
#define RB_UEP6_TX_EN 0x40
#define RB_UEP6_RX_EN 0x80
/* UEP_MOD offset 3 */
#define RB_UEP7_BUF_MOD 0x01
#define RB_UEP7_TX_EN 0x04
#define RB_UEP7_RX_EN 0x08
/* each nibble is an ep index map : {hi_lo_nibble(1), reg_offset(3)} */
#define UEP_MOD_MAP 0x3a209180
#define uep_mod_offset(ep) (((UEP_MOD_MAP >> (ep * 4)) & 3))
#define uep_mod_shift(ep) (((UEP_MOD_MAP >> (ep * 4)) & 8) ? 4 : 0)
union _uep_rt_ctrl
{
uint8_t reg;
struct
{
uint8_t res_mask : 2; // RW, response control bits
uint8_t res_no : 1; // RW, not expecting response
uint8_t tog_mask : 2; // RW, transmit/expect DATAx
uint8_t autotog : 1; // RW, auto DATAx toggle (not for EP0)
uint8_t resv_6 : 2;
};
};
#define RB_UEP_RES_MASK 0x03
#define RB_UEP_RES_NO 0x04
#define RB_UEP_TOG_MASK 0x18
#define RB_UEP_AUTOTOG 0x20
#define UEP_RES_ACK 0
#define UEP_RES_NYET 1
#define UEP_RES_NAK 2
#define UEP_RES_STALL 3
#define UEP_TOG_DATA0 0
#define UEP_TOG_DATA1 1
#define UEP_TOG_DATA2 2
#define UEP_TOG_MDATA 3
#define RB_UEP_RES_ACK (UEP_RES_ACK << 0)
#define RB_UEP_RES_NYET (UEP_RES_NYET << 0)
#define RB_UEP_RES_NAK (UEP_RES_NAK << 0)
#define RB_UEP_RES_STALL (UEP_RES_STALL << 0)
#define RB_UEP_TOG_DATA0 (UEP_TOG_DATA0 << 3)
#define RB_UEP_TOG_DATA1 (UEP_TOG_DATA1 << 3)
#define RB_UEP_TOG_DATA2 (UEP_TOG_DATA2 << 3)
#define RB_UEP_TOG_MDATA (UEP_TOG_MDATA << 3)
union _uh_rt_ctrl
{
uint8_t reg;
struct
{
uint8_t res_mask : 2; // RW, response control bits
uint8_t res_no : 1; // RW, not expecting response
uint8_t tog_mask : 2; // RW, expected DATAx
uint8_t autotog : 1; // RW, auto DATAx toggle
uint8_t data_no : 1; // RW, not expecting data
uint8_t resv_7 : 1;
};
};
#define RB_UH_RES_MASK 0x03
#define RB_UH_RES_NO 0x04
#define RB_UH_TOG_MASK 0x18
#define RB_UH_AUTOTOG 0x20
#define RB_UH_DATA_NO 0x40
#define UH_RES_ACK 0
#define UH_RES_NYET 1
#define UH_RES_NAK 2
#define UH_RES_STALL 3
#define UH_TOG_DATA0 0
#define UH_TOG_DATA1 1
#define UH_TOG_DATA2 2
#define UH_TOG_MDATA 3
#define RB_UH_RES_ACK (UH_RES_ACK << 0)
#define RB_UH_RES_NYET (UH_RES_NYET << 0)
#define RB_UH_RES_NAK (UH_RES_NAK << 0)
#define RB_UH_RES_STALL (UH_RES_STALL << 0)
#define RB_UH_TOG_DATA0 (UH_TOG_DATA0 << 3)
#define RB_UH_TOG_DATA1 (UH_TOG_DATA1 << 3)
#define RB_UH_TOG_DATA2 (UH_TOG_DATA2 << 3)
#define RB_UH_TOG_MDATA (UH_TOG_MDATA << 3)
union _uhost_ctrl
{
uint8_t reg;
struct
{
uint8_t bus_reset : 1; // RW, USB host transmit bus reset signal
uint8_t bus_suspend : 1; // RW, USB host transmit suspend signal
uint8_t bus_resume : 1; // RW, wake up device when bus suspended
uint8_t resv_3 : 4;
uint8_t autosof_en : 1; // RW, Auto generate SOF packet enable (CH569)
};
};
#define RB_UH_BUS_RESET 0x01
#define RB_UH_BUS_SUSPEND 0x02
#define RB_UH_BUS_RESUME 0x04
#define RB_UH_AUTOSOF_EN 0x80
union _uh_ep_mod
{
uint8_t reg;
struct
{
uint8_t rbuf_mod : 1; // RW, CH567/CH568 only
uint8_t resv_1 : 2;
uint8_t rx_en : 1; // RW, enable HOST receiver (IN)
uint8_t tbuf_mod : 1; // RW, CH567/CH568 only
uint8_t resv_5 : 1;
uint8_t tx_en : 1; // RW, enable HOST transmitter (SETUP/OUT)
uint8_t resv_7 : 1;
};
};
#define RB_UH_RBUF_MOD 0x01
#define RB_UH_RX_EN 0x08
#define RB_UH_TBUF_MOD 0x10
#define RB_UH_TX_EN 0x40
union _uh_ep_pid
{
uint16_t reg;
struct
{
uint8_t epnum_mask : 4; // RW, Set endpoint number of the target device
uint8_t token_mask : 4; // RW, Set the token PID packet identification
uint8_t resv;
};
};
#define RB_UH_EPNUM_MASK 0x0f
#define RB_UH_TOKEN_MASK 0xf0
#ifndef SOC_SERIES_CH569
union _uh_setup
{
uint8_t reg;
struct
{
uint8_t resv_0 : 6;
uint8_t sof_en : 1; // WO, Auto generate SOF packet enable
uint8_t resv_7 : 1;
};
};
#define RB_UH_SOF_EN 0x40
#endif
/*
* USBHS Global Registers :
*
* 0x00 R8_USB_CTRL: USB control register
* 0x02 R8_USB_INT_EN: USB interrupt enable register
* 0x03 R8_USB_DEV_AD: USB addresss register
* 0x04 R16_USB_FRAME_NO: USBHS frame number register
* 0x06 R8_USB_SUSPEND: USB suspend control register
* 0x08 R8_USB_SPD_TYPE: USB current speed type register
* 0x09 R8_USB_MIS_ST: USB miscellaneous status register
* 0x0a R8_USB_INT_FG: USB interrupt flag register
* 0x0b R8_USB_INT_ST: USB interrpt status register
* 0x0c R16_USB_RX_LEN: USB reception length register
*/
/*
* CH565/CH569 USBHS DEVICE Related Registers :
*
* 0x10 R8_UEP4_1_MOD: Endpoint 1(9) / 4(8/12) mode control register
* 0x11 R8_UEP2_3_MOD: Endpoint 2(10) / 3(11) mode control register
* 0x12 R8_UEP5_6_MOD: Endpoint 5(13) / 6(14) mode control register
* 0x13 R8_UEP7_MOD: Endpoint 7(15) mode control register
* 0x14 R32_UEP0_RT_DMA: Start address of endpoint0 buffer
* 0x18 R32_UEP1_RX_DMA: Start address of endpoint 1(9) receive buffer
* 0x1c R32_UEP2_RX_DMA: Start address of endpoint 2(10) receive buffer
* 0x20 R32_UEP3_RX_DMA: Start address of endpoint 3(11) receive buffer
* 0x24 R32_UEP4_RX_DMA: Start address of endpoint 4(8/12) receive buffer
* 0x28 R32_UEP5_RX_DMA: Start address of endpoint 5(13) receive buffer
* 0x2c R32_UEP6_RX_DMA: Start address of endpoint 6(14) receive buffer
* 0x30 R32_UEP7_RX_DMA: Start address of endpoint 7(15) receive buffer
* 0x34 R32_UEP1_TX_DMA: Start address of endpoint 1(9) transmit buffer
* 0x38 R32_UEP2_TX_DMA: Start address of endpoint 2(10) transmit buffer
* 0x3c R32_UEP3_TX_DMA: Start address of endpoint 3(11) transmit buffer
* 0x40 R32_UEP4_TX_DMA: Start address of endpoint 4(8/12) transmit buffer
* 0x44 R32_UEP5_TX_DMA: Start address of endpoint 5(13) transmit buffer
* 0x48 R32_UEP6_TX_DMA: Start address of endpoint 6(14) transmit buffer
* 0x4c R32_UEP7_TX_DMA: Start address of endpoint 7(15) transmit buffer
* 0x50 R16_UEP0_MAX_LEN: Endpoint 0 receive maximum length packet register
* 0x54 R16_UEP1_MAX_LEN: Endpoint 1(9) receive maximum length packet register
* 0x58 R16_UEP2_MAX_LEN: Endpoint 2(10) receive maximum length packet register
* 0x5c R16_UEP3_MAX_LEN: Endpoint 3(11) receive maximum length packet register
* 0x60 R16_UEP4_MAX_LEN: Endpoint 4(8/12) receive maximum length packet register
* 0x64 R16_UEP5_MAX_LEN: Endpoint 5(13) receive maximum length packet register
* 0x68 R16_UEP6_MAX_LEN: Endpoint 6(14) receive maximum length packet register
* 0x6c R16_UEP7_MAX_LEN: Endpoint 7(15) receive maximum length packet register
* 0x70 R16_UEP0_T_LEN: Endpoint 0 transmission length register
* 0x72 R8_UEP0_TX_CTRL: Endpoint 0 transmit control register
* 0x73 R8_UEP0_RX_CTRL: Endpoint 0 receive control register
* 0x74 R16_UEP1_T_LEN: Endpoint 1(9) transmission length register
* 0x76 R8_UEP1_TX_CTRL: Endpoint 1(9) transmit control register
* 0x77 R8_UEP1_RX_CTRL: Endpoint 1(9) receive control register
* 0x78 R16_UEP2_T_LEN: Endpoint 2(10) transmission length register
* 0x7a R8_UEP2_TX_CTRL: Endpoint 2(10) transmit control register
* 0x7b R8_UEP2_RX_CTRL: Endpoint 2(10) receive control register
* 0x7c R16_UEP3_T_LEN: Endpoint 3(11) transmission length register
* 0x7e R8_UEP3_TX_CTRL: Endpoint 3(11) transmit control register
* 0x7f R8_UEP3_RX_CTRL: Endpoint 3(11) receive control register
* 0x80 R16_UEP4_T_LEN: Endpoint 4(8/12) transmission length register
* 0x82 R8_UEP4_TX_CTRL: Endpoint 4(8/12) transmit control register
* 0x83 R8_UEP4_RX_CTRL: Endpoint 4(8/12) receive control register
* 0x84 R16_UEP5_T_LEN: Endpoint 5(13) transmission length register
* 0x86 R8_UEP5_TX_CTRL: Endpoint 5(13) transmit control register
* 0x87 R8_UEP5_RX_CTRL: Endpoint 5(13) receive control register
* 0x88 R16_UEP6_T_LEN: Endpoint 6(14) transmission length register
* 0x8a R8_UEP6_TX_CTRL: Endpoint 6(14) transmit control register
* 0x8b R8_UEP6_RX_CTRL: Endpoint 6(14) receive control register
* 0x8c R16_UEP7_T_LEN: Endpoint 7(15) transmission length register
* 0x8e R8_UEP7_TX_CTRL: Endpoint 7(15) transmit control register
* 0x8f R8_UEP7_RX_CTRL: Endpoint 7(15) receive control register
*
* CH567/CH568 USBHS DEVICE Related Registers :
*
* 0x10 UEP4_1_MOD: Endpoint 1/4 mode control register
* 0x11 UEP2_3_MOD: Endpoint 2/3 mode control register
* 0x14 UEP0_DMA: Endpoint 0 DMA buffer start address
* 0x18 UEP1_DMA: Endpoint 1 DMA buffer start address
* 0x1c UEP2_DMA: Endpoint 2 DMA buffer start address
* 0x20 UEP3_DMA: Endpoint 3 DMA buffer start address
* 0x24 UEP0_MAX_LEN: Endpoint 0 receive maximum length packet register
* 0x28 UEP1_MAX_LEN: Endpoint 1 receive maximum length packet register
* 0x2c UEP2_MAX_LEN: Endpoint 2 receive maximum length packet register
* 0x30 UEP3_MAX_LEN: Endpoint 3 receive maximum length packet register
* 0x34 UEP4_MAX_LEN: Endpoint 4 receive maximum length packet register
* 0x38 UEP0_T_LEN: Endpoint 0 transmission length register
* 0x3a UEP0_TX_CTRL: Endpoint 0 transmit control register
* 0x3b UEP0_RX_CTRL: Endpoint 0 receive control register
* 0x3c UEP1_T_LEN: Endpoint 1 transmission length register
* 0x3e UEP1_TX_CTRL: Endpoint 1 transmit control register
* 0x3f UEP1_RX_CTRL: Endpoint 1 receive control register
* 0x40 UEP2_T_LEN: Endpoint 2 transmission length register
* 0x42 UEP2_TX_CTRL: Endpoint 2 transmit control register
* 0x43 UEP2_RX_CTRL: Endpoint 2 receive control register
* 0x44 UEP2_T_LEN: Endpoint 3 transmission length register
* 0x46 UEP2_TX_CTRL: Endpoint 3 transmit control register
* 0x47 UEP2_RX_CTRL: Endpoint 3 receive control register
* 0x48 UEP4_T_LEN: Endpoint 4 transmission length register
* 0x4a UEP4_TX_CTRL: Endpoint 4 transmit control register
* 0x4b UEP4_RX_CTRL: Endpoint 4 receive control register
*/
/*
* CH565/CH569 USBHS HOST Related Registers :
*
* 0x01 R8_UHOST_CTRL: USB host control register
* 0x11 R8_UH_EP_MOD: USB host endpoint mode register
* 0x1c R32_UH_RX_DMA: USB host receive buffer start address
* 0x3c R32_UH_TX_DMA: USB host transmit buffer start address
* 0x58 R16_UH_MAX_LEN: USB host reception maximum length packet register
* 0x78 R16_UH_EP_PID: USB host token setting register
* 0x7b R8_UH_RX_CTRL: USB host reception endpoint control register
* 0x7c R16_UH_TX_LEN: USB host transmission length register
* 0x7e R8_UH_TX_CTRL: USB host transmission endpoint control register
* 0x80 R16_UH_SPLIT_DATA: USB host transmit SPLIT packet data
*
* CH567/CH568 USBHS HOST Related Registers :
*
* 0x01 UHOST_CTRL: USB host control register
* 0x11 UH_EP_MOD: USB host endpoint mode register
* 0x1c UH_RX_DMA: USB host receive buffer start address
* 0x20 UH_TX_DMA: USB host transmit buffer start address
* 0x2c UH_RX_MAX_LEN: USB host reception maximum length packet register
* 0x3e UH_SETUP: USB host aux config register
* 0x40 UH_EP_PID: USB host token setting register
* 0x43 UH_RX_CTRL: USB host reception endpoint control register
* 0x44 UH_TX_LEN: USB host transmission length register
* 0x46 UH_TX_CTRL: USB host transmission endpoint control register
* 0x48 UH_SPLIT_DATA: USB host transmit SPLIT packet data
*/
struct usbhs_registers
{
union
{
/* USB Global Registers */
struct
{
union _usb_ctrl CTRL;
uint8_t stuff_01;
union _usb_int_en INT_EN;
uint8_t DEV_AD;
uint16_t FRAME_NO;
union _usb_suspend SUSPEND;
uint8_t resv_07;
union _usb_spd_type SPD_TYPE;
union _usb_mis_st MIS_ST;
union _usb_int_fg INT_FG;
union _usb_int_st INT_ST;
uint16_t RX_LEN;
};
/* USB DEVICE Related Registers */
struct
{
uint32_t stuff_gr[4];
union
{
uint8_t UEP_MOD[4];
uint32_t R32_UEP_MOD;
};
#ifdef SOC_SERIES_CH569
union
{
struct
{
uint32_t UEP0_RT_DMA;
uint32_t stuff_rt[14];
};
struct
{
uint32_t UEP_RX_DMA[8]; // UEP_RX_DMA[0] NOT exist
uint32_t stuff_rx[7];
};
struct
{
uint32_t stuff_tx[7];
uint32_t UEP_TX_DMA[8]; // UEP_TX_DMA[0] NOT exist
};
};
#else
struct
{
uint16_t reg;
uint16_t resv;
} UEP_DMA[4];
#endif
struct
{
uint16_t reg;
uint16_t resv;
} UEP_MAX_LEN[UEP_ADDRESS_MAX + 1];
struct
{
uint16_t t_len; // MSB 5 bits are fixed to 0
union _uep_rt_ctrl TX_CTRL;
union _uep_rt_ctrl RX_CTRL;
} UEP_CTRL[UEP_ADDRESS_MAX + 1];
};
/* USB HOST Related Registers */
#ifdef SOC_SERIES_CH569
struct
{
uint8_t stuff_00;
union _uhost_ctrl UHOST_CTRL;
uint8_t stuff_02[15];
union _uh_ep_mod UH_EP_MOD;
uint8_t stuff_12[10];
uint32_t UH_RX_DMA;
uint32_t stuff_20[7];
uint32_t UH_TX_DMA;
uint32_t stuff_40[6];
uint16_t UH_MAX_LEN;
uint16_t stuff_5a[15];
union _uh_ep_pid UH_EP_PID;
uint8_t stuff_7a;
union _uh_rt_ctrl UH_RX_CTRL;
uint16_t UH_TX_LEN;
union _uh_rt_ctrl UH_TX_CTRL;
uint8_t stuff_7f;
uint16_t UH_SPLIT_DATA;
uint16_t stuff_82[7];
};
#else
struct
{
uint8_t stuff_00;
union _uhost_ctrl UHOST_CTRL;
uint8_t stuff_02[15];
union _uh_ep_mod UH_EP_MOD;
uint8_t stuff_12[10];
uint32_t UH_RX_DMA;
uint32_t UH_TX_DMA;
uint32_t stuff_24[2];
uint16_t UH_MAX_LEN;
uint16_t stuff_2e[8];
uint8_t UH_SETUP;
uint8_t stuff_3f;
union _uh_ep_pid UH_EP_PID;
uint8_t stuff_42;
union _uh_rt_ctrl UH_RX_CTRL;
uint16_t UH_TX_LEN;
union _uh_rt_ctrl UH_TX_CTRL;
uint8_t stuff_47;
uint16_t UH_SPLIT_DATA;
uint16_t stuff_4a;
};
#endif
};
} __packed;
#ifdef SOC_SERIES_CH569
CHECK_STRUCT_SIZE(struct usbhs_registers, 0x90);
#else
CHECK_STRUCT_SIZE(struct usbhs_registers, 0x4c);
#endif
rt_inline void _uep_mod_set(volatile struct usbhs_registers *usbhs,
int ep_idx, uint8_t mod)
{
int reg_n = uep_mod_offset(ep_idx);
int shift = uep_mod_shift(ep_idx);
int mask = 0x0f << shift;
/* ep_idx must be 1 ~ UEP_ADDRESS_MAX */
usbhs->UEP_MOD[reg_n] = (usbhs->UEP_MOD[reg_n] & ~mask) | (mod << shift);
}
rt_inline uint8_t _uep_mod_get(volatile struct usbhs_registers *usbhs, int ep_idx)
{
int reg_n = uep_mod_offset(ep_idx);
int shift = uep_mod_shift(ep_idx);
/* ep_idx should be 1 ~ UEP_ADDRESS_MAX */
return (usbhs->UEP_MOD[reg_n] >> shift) & 0x0f;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -21,6 +21,10 @@
#define SOC_SERIES_CH569
#endif
#ifndef __packed
#define __packed __attribute__((packed))
#endif
#define CHECK_STRUCT_SIZE(s, size) \
static_assert(sizeof(s) == size, #s " has wrong size")
@ -29,10 +33,10 @@
#define FLASH_BASE_ADDRESS 0x00000000
#define RAMS_BASE_ADDRESS 0x20000000
#define RAMX_BASE_ADDRESS 0x20020000
#define BUS8_BASE_ADDRESS 0x80000000
#ifdef SOC_SERIES_CH569
#define RAMX_BASE_ADDRESS 0x20020000
#define RAMS_SIZE 16
#else
#define RAMS_SIZE 32

View File

@ -38,9 +38,9 @@ CONFIG_RT_KSERVICE_USING_STDLIB=y
#
CONFIG_RT_USING_SEMAPHORE=y
CONFIG_RT_USING_MUTEX=y
# CONFIG_RT_USING_EVENT is not set
CONFIG_RT_USING_EVENT=y
CONFIG_RT_USING_MAILBOX=y
# CONFIG_RT_USING_MESSAGEQUEUE is not set
CONFIG_RT_USING_MESSAGEQUEUE=y
# CONFIG_RT_USING_SIGNALS is not set
#
@ -78,7 +78,7 @@ CONFIG_ARCH_RISCV=y
#
CONFIG_RT_USING_COMPONENTS_INIT=y
CONFIG_RT_USING_USER_MAIN=y
CONFIG_RT_MAIN_THREAD_STACK_SIZE=2048
CONFIG_RT_MAIN_THREAD_STACK_SIZE=1024
CONFIG_RT_MAIN_THREAD_PRIORITY=10
# CONFIG_RT_USING_LEGACY is not set
CONFIG_RT_USING_MSH=y

View File

@ -2,9 +2,11 @@ from building import *
cwd = GetCurrentDir()
app = ARGUMENTS.get('app', "main")
src = Split("""
main.c
""")
{}.c
""".format(app))
path = [cwd, str(Dir('#'))]

View File

@ -361,6 +361,52 @@ static void test_pwm(void)
#define test_pwm() do {} while(0)
#endif
#ifdef RT_USING_USB_DEVICE
#if !defined(RT_USING_EVENT) || !defined(RT_USING_MESSAGEQUEUE)
#error "event flag or message queue IPC not enabled"
#endif
static struct rt_thread *udvcom_thread;
static rt_device_t vcom;
static void usbd_vcom_thread(void *param)
{
char ch;
while (1)
{
while (rt_device_read(vcom, 0, &ch, 1) != 1)
rt_thread_delay(1);
rt_kprintf("(%2d) %02x:%c\n", rt_device_write(vcom, 0, &ch, 1), ch, ch);
rt_pin_write(LED1_PIN, (ch & 1) ? PIN_LOW : PIN_HIGH);
}
}
static void test_usbd()
{
char name[] = "vcom";
vcom = rt_device_find(name);
if (vcom && rt_device_open(vcom, RT_DEVICE_FLAG_INT_RX) == RT_EOK)
{
rt_kprintf("%s opened\n", name);
rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
rt_pin_write(LED1_PIN, PIN_LOW);
udvcom_thread = rt_thread_create("udvcom", usbd_vcom_thread, vcom,
512, 20, 50);
if (udvcom_thread != RT_NULL)
rt_thread_startup(udvcom_thread);
else
rt_kprintf("usvcom thread create failed !\n");
rt_device_write(vcom, 0, name, rt_strlen(name));
}
}
#else
#define test_usbd() do {} while(0)
#endif
void main(void)
{
uint32_t wdog_timeout = 32;
@ -372,6 +418,7 @@ void main(void)
test_hwtimer();
test_spi_master();
test_pwm();
test_usbd();
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
rt_pin_write(LED0_PIN, led0 = PIN_LOW);

View File

@ -1,187 +1,189 @@
ENTRY( _start )
__stack_size = 2048;
__stack_size = 1536;
PROVIDE( _stack_size = __stack_size );
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 96K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K
RAMX (xrw) : ORIGIN = 0x20020000, LENGTH = 32K
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 96K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K
RAMX (xrw) : ORIGIN = 0x20020000, LENGTH = 32K
}
SECTIONS
{
.init :
{
_sinit = .;
. = ALIGN(4);
KEEP(*(SORT_NONE(.init)))
. = ALIGN(4);
_einit = .;
} >FLASH AT>FLASH
.init :
{
_sinit = .;
. = ALIGN(4);
KEEP(*(SORT_NONE(.init)))
. = ALIGN(4);
_einit = .;
} >FLASH AT>FLASH
.vector :
{
*(.vector);
. = ALIGN(64);
. = ALIGN(64);
} >FLASH AT>FLASH
.text :
{
. = ALIGN(4);
*(.text)
*(.text.*)
*(.rodata)
*(.rodata*)
*(.glue_7)
*(.glue_7t)
*(.gnu.linkonce.t.*)
/* section information for finsh shell */
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
/* section information for initial. */
. = ALIGN(4);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(4);
/* section information for modules */
. = ALIGN(4);
__rtmsymtab_start = .;
KEEP(*(RTMSymTab))
__rtmsymtab_end = .;
. = ALIGN(4);
} >FLASH AT>FLASH
.fini :
{
KEEP(*(SORT_NONE(.fini)))
. = ALIGN(4);
} >FLASH AT>FLASH
PROVIDE( _etext = . );
PROVIDE( _eitcm = . );
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH AT>FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH AT>FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH AT>FLASH
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >FLASH AT>FLASH
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >FLASH AT>FLASH
.dalign :
{
. = ALIGN(4);
PROVIDE(_data_vma = .);
} >RAM AT>FLASH
.dlalign :
{
. = ALIGN(4);
PROVIDE(_data_lma = .);
} >FLASH AT>FLASH
.data :
{
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.sdata2.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
. = ALIGN(4);
PROVIDE( _edata = .);
} >RAM AT>FLASH
.bss :
{
. = ALIGN(4);
PROVIDE( _sbss = .);
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss*)
*(.gnu.linkonce.b.*)
*(COMMON*)
. = ALIGN(4);
PROVIDE( _ebss = .);
} >RAM AT>FLASH
PROVIDE( _end = _ebss);
PROVIDE( end = . );
.dmadata :
.text :
{
. = ALIGN(4);
*(.text)
*(.text.*)
*(.rodata)
*(.rodata*)
*(.glue_7)
*(.glue_7t)
*(.gnu.linkonce.t.*)
/* section information for finsh shell */
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
/* section information for initial. */
. = ALIGN(4);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(4);
/* section information for modules */
. = ALIGN(4);
__rtmsymtab_start = .;
KEEP(*(RTMSymTab))
__rtmsymtab_end = .;
. = ALIGN(4);
} >FLASH AT>FLASH
.fini :
{
KEEP(*(SORT_NONE(.fini)))
. = ALIGN(4);
} >FLASH AT>FLASH
PROVIDE( _etext = . );
PROVIDE( _eitcm = . );
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH AT>FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH AT>FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH AT>FLASH
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >FLASH AT>FLASH
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >FLASH AT>FLASH
.dalign :
{
. = ALIGN(4);
PROVIDE(_data_vma = .);
} >RAM AT>FLASH
.dlalign :
{
. = ALIGN(4);
PROVIDE(_data_lma = .);
} >FLASH AT>FLASH
.data :
{
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.sdata2.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
. = ALIGN(4);
PROVIDE( _edata = .);
} >RAM AT>FLASH
.bss :
{
. = ALIGN(4);
PROVIDE( _sbss = .);
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss*)
*(.gnu.linkonce.b.*)
*(COMMON*)
. = ALIGN(4);
PROVIDE( _ebss = .);
} >RAM AT>FLASH
PROVIDE( _end = _ebss);
PROVIDE( end = . );
.dmadata :
{
. = ALIGN(16);
PROVIDE( _dmadata_start = .);
/* first 8 bytes are reserved for USB ep0 SETUP */
. = . + 8;
. = ALIGN(16);
*(.dmadata*)
*(.dmadata.*)
. = ALIGN(16);
@ -195,5 +197,5 @@ SECTIONS
PROVIDE(_susrstack = . );
. = . + __stack_size;
PROVIDE( _eusrstack = .);
} >RAM
} >RAM
}

View File

@ -25,7 +25,9 @@
#define RT_USING_SEMAPHORE
#define RT_USING_MUTEX
#define RT_USING_EVENT
#define RT_USING_MAILBOX
#define RT_USING_MESSAGEQUEUE
/* Memory Management */
@ -48,7 +50,7 @@
#define RT_USING_COMPONENTS_INIT
#define RT_USING_USER_MAIN
#define RT_MAIN_THREAD_STACK_SIZE 2048
#define RT_MAIN_THREAD_STACK_SIZE 1024
#define RT_MAIN_THREAD_PRIORITY 10
#define RT_USING_MSH
#define RT_USING_FINSH