switch khci to use generic chipidea fs regs definition

This commit is contained in:
hathach 2021-12-06 20:03:36 +07:00
parent 948bb53e8b
commit 5a35c8c81f
2 changed files with 149 additions and 55 deletions

View File

@ -0,0 +1,89 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021, Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#ifndef _CI_FS_TYPE_H_
#define _CI_FS_TYPE_H_
#ifdef __cplusplus
extern "C" {
#endif
// reserved 3 bytes
#define _rsvd3 uint8_t TU_RESERVED[3]
// Note Kinetis requires byte write access to usb register
// declare it as uint32_t will cause data error
typedef struct {
volatile uint8_t perid; _rsvd3; // 00 Peripheral ID register
volatile uint8_t idcomp; _rsvd3; // 04 Peripheral ID complement register
volatile uint8_t rev; _rsvd3; // 08 Peripheral revision register
volatile uint8_t add_info; _rsvd3; // 0C Peripheral additional info register
volatile uint8_t otg_int_stat; _rsvd3; // 10 OTG Interrupt Status Register
volatile uint8_t otg_int_en; _rsvd3; // 14 OTG Interrupt Control Register
volatile uint8_t otg_stat; _rsvd3; // 18 OTG Status Register
volatile uint8_t OTG_CTRL; _rsvd3; // 1C OTG Control register
volatile uint8_t reserved_20[24*4]; // 20..7F Reserved
volatile uint8_t int_stat; _rsvd3; // 80 Interrupt status register
volatile uint8_t int_en; _rsvd3; // 84 Interrupt enable register
volatile uint8_t err_stat; _rsvd3; // 88 Error interrupt status register
volatile uint8_t err_en; _rsvd3; // 8C Error interrupt enable register
volatile uint8_t stat; _rsvd3; // 90 Status register
volatile uint8_t ctl; _rsvd3; // 94 Control register
volatile uint8_t addr; _rsvd3; // 98 Address register
volatile uint8_t bdt_page1; _rsvd3; // 9C BDT page register 1
volatile uint8_t frm_numl; _rsvd3; // A0 Frame number register
volatile uint8_t frm_numh; _rsvd3; // A4 Frame number register
volatile uint8_t token; _rsvd3; // A8 Token register
volatile uint8_t sof_thld; _rsvd3; // AC SOF threshold register
volatile uint8_t bdt_page2; _rsvd3; // B0 BDT page register 2
volatile uint8_t bdt_page3; _rsvd3; // B4 BDT page register 3
volatile uint8_t reserved_b8; _rsvd3; // B8 Reserved
volatile uint8_t reserved_bc; _rsvd3; // BC Reserved
struct {
volatile uint8_t endpt; _rsvd3; // C0..FF Endpoint control register
}ep[16];
// Kinetis specific extension
volatile uint8_t usbctrl; _rsvd3; // 100
volatile uint8_t observe; _rsvd3; // 104
volatile uint8_t control; _rsvd3; // 108
volatile uint8_t usbtrc0; _rsvd3; // 10C
volatile uint8_t reserved_110[4]; // 110
volatile uint8_t usbfrmadjust; _rsvd3; // 114
} ci_fs_reg_t;
TU_VERIFY_STATIC(offsetof(ci_fs_reg_t, bdt_page1) == 0x9C, "incorrect size");
TU_VERIFY_STATIC(offsetof(ci_fs_reg_t, bdt_page2) == 0xB0, "incorrect size");
TU_VERIFY_STATIC(offsetof(ci_fs_reg_t, bdt_page3) == 0xB4, "incorrect size");
TU_VERIFY_STATIC(offsetof(ci_fs_reg_t, ep) == 0xC0, "incorrect size");
#ifdef __cplusplus
}
#endif
#endif

View File

@ -30,6 +30,7 @@
#if TUSB_OPT_DEVICE_ENABLED && defined(DCD_ATTR_CONTROLLER_CHIPIDEA_FS)
#include "device/dcd.h"
#include "ci_fs_type.h"
#if TU_CHECK_MCU(OPT_MCU_MKL25ZXX, OPT_MCU_K32L2BXX)
#include "ci_fs_kinetis.h"
@ -37,6 +38,7 @@
#error "Unsupported MCUs"
#endif
#define CI_REG ((ci_fs_reg_t*) CI_FS_REG_BASE)
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
@ -136,22 +138,22 @@ static void prepare_next_setup_packet(uint8_t rhport)
static void process_stall(uint8_t rhport)
{
for (int i = 0; i < 16; ++i) {
unsigned const endpt = KHCI->ENDPOINT[i].ENDPT;
unsigned const endpt = CI_REG->ep[i].endpt;
if (endpt & USB_ENDPT_EPSTALL_MASK) {
// prepare next setup if endpoint0
if ( i == 0 ) prepare_next_setup_packet(rhport);
// clear stall bit
KHCI->ENDPOINT[i].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK;
CI_REG->ep[i].endpt = endpt & ~USB_ENDPT_EPSTALL_MASK;
}
}
}
static void process_tokdne(uint8_t rhport)
{
const unsigned s = KHCI->STAT;
KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
const unsigned s = CI_REG->stat;
CI_REG->int_stat = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
uint8_t const epnum = (s >> USB_STAT_ENDP_SHIFT);
uint8_t const dir = (s & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT;
@ -172,7 +174,7 @@ static void process_tokdne(uint8_t rhport)
ep->odd = odd ^ 1;
if (pid == TOK_PID_SETUP) {
dcd_event_setup_received(rhport, bd->addr, true);
KHCI->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
CI_REG->ctl &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
return;
}
@ -201,7 +203,7 @@ static void process_tokdne(uint8_t rhport)
if (_dcd.addr) {
/* When the transfer was the SetAddress,
* the device address should be updated here. */
KHCI->ADDR = _dcd.addr;
CI_REG->addr = _dcd.addr;
_dcd.addr = 0;
}
prepare_next_setup_packet(rhport);
@ -210,15 +212,15 @@ static void process_tokdne(uint8_t rhport)
static void process_bus_reset(uint8_t rhport)
{
KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
KHCI->CTL |= USB_CTL_ODDRST_MASK;
KHCI->ADDR = 0;
KHCI->INTEN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK |
USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
CI_REG->usbctrl &= ~USB_USBCTRL_SUSP_MASK;
CI_REG->ctl |= USB_CTL_ODDRST_MASK;
CI_REG->addr = 0;
CI_REG->int_en = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK |
USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
KHCI->ENDPOINT[0].ENDPT = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
CI_REG->ep[0].endpt = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
for (unsigned i = 1; i < 16; ++i) {
KHCI->ENDPOINT[i].ENDPT = 0;
CI_REG->ep[i].endpt = 0;
}
buffer_descriptor_t *bd = _dcd.bdt[0][0];
for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
@ -235,18 +237,18 @@ static void process_bus_reset(uint8_t rhport)
tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0]));
_dcd.addr = 0;
prepare_next_setup_packet(rhport);
KHCI->CTL &= ~USB_CTL_ODDRST_MASK;
CI_REG->ctl &= ~USB_CTL_ODDRST_MASK;
dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
}
static void process_bus_sleep(uint8_t rhport)
{
// Enable resume & disable suspend interrupt
const unsigned inten = KHCI->INTEN;
const unsigned inten = CI_REG->int_en;
KHCI->INTEN = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
KHCI->USBTRC0 |= USB_USBTRC0_USBRESMEN_MASK;
KHCI->USBCTRL |= USB_USBCTRL_SUSP_MASK;
CI_REG->int_en = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
CI_REG->usbtrc0 |= USB_USBTRC0_USBRESMEN_MASK;
CI_REG->usbctrl |= USB_USBCTRL_SUSP_MASK;
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
}
@ -254,11 +256,11 @@ static void process_bus_sleep(uint8_t rhport)
static void process_bus_resume(uint8_t rhport)
{
// Enable suspend & disable resume interrupt
const unsigned inten = KHCI->INTEN;
const unsigned inten = CI_REG->int_en;
KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; // will also clear USB_USBTRC0_USB_RESUME_INT_MASK
KHCI->USBTRC0 &= ~USB_USBTRC0_USBRESMEN_MASK;
KHCI->INTEN = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
CI_REG->usbctrl &= ~USB_USBCTRL_SUSP_MASK; // will also clear USB_USBTRC0_USB_RESUME_INT_MASK
CI_REG->usbtrc0 &= ~USB_USBTRC0_USBRESMEN_MASK;
CI_REG->int_en = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
}
@ -270,16 +272,19 @@ void dcd_init(uint8_t rhport)
{
(void) rhport;
KHCI->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
while (KHCI->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
CI_REG->usbtrc0 |= USB_USBTRC0_USBRESET_MASK;
while (CI_REG->usbtrc0 & USB_USBTRC0_USBRESET_MASK);
tu_memclr(&_dcd, sizeof(_dcd));
KHCI->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
KHCI->BDTPAGE1 = (uint8_t)((uintptr_t)_dcd.bdt >> 8);
KHCI->BDTPAGE2 = (uint8_t)((uintptr_t)_dcd.bdt >> 16);
KHCI->BDTPAGE3 = (uint8_t)((uintptr_t)_dcd.bdt >> 24);
CI_REG->usbtrc0 |= TU_BIT(6); /* software must set this bit to 1 */
KHCI->INTEN = USB_INTEN_USBRSTEN_MASK;
uintptr_t const bdt_addr = (uintptr_t)_dcd.bdt;
CI_REG->bdt_page1 = tu_u32_byte1(bdt_addr);
CI_REG->bdt_page2 = tu_u32_byte2(bdt_addr);
CI_REG->bdt_page3 = tu_u32_byte3(bdt_addr);
CI_REG->int_en = USB_INTEN_USBRSTEN_MASK;
dcd_connect(rhport);
NVIC_ClearPendingIRQ(USB0_IRQn);
@ -308,27 +313,27 @@ void dcd_remote_wakeup(uint8_t rhport)
{
(void) rhport;
KHCI->CTL |= USB_CTL_RESUME_MASK;
CI_REG->ctl |= USB_CTL_RESUME_MASK;
unsigned cnt = SystemCoreClock / 1000;
while (cnt--) __NOP();
KHCI->CTL &= ~USB_CTL_RESUME_MASK;
CI_REG->ctl &= ~USB_CTL_RESUME_MASK;
}
void dcd_connect(uint8_t rhport)
{
(void) rhport;
KHCI->USBCTRL = 0;
KHCI->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK;
KHCI->CTL |= USB_CTL_USBENSOFEN_MASK;
CI_REG->usbctrl = 0;
CI_REG->control |= USB_CONTROL_DPPULLUPNONOTG_MASK;
CI_REG->ctl |= USB_CTL_USBENSOFEN_MASK;
}
void dcd_disconnect(uint8_t rhport)
{
(void) rhport;
KHCI->CTL = 0;
KHCI->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
CI_REG->ctl = 0;
CI_REG->control &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
}
//--------------------------------------------------------------------+
@ -353,7 +358,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
unsigned val = USB_ENDPT_EPCTLDIS_MASK;
val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK: 0;
val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
KHCI->ENDPOINT[epn].ENDPT |= val;
CI_REG->ep[epn].endpt |= val;
if (xfer != TUSB_XFER_ISOCHRONOUS) {
bd[odd].dts = 1;
@ -371,7 +376,7 @@ void dcd_edpt_close_all(uint8_t rhport)
const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
NVIC_DisableIRQ(USB0_IRQn);
for (unsigned i = 1; i < 16; ++i) {
KHCI->ENDPOINT[i].ENDPT = 0;
CI_REG->ep[i].endpt = 0;
}
if (ie) NVIC_EnableIRQ(USB0_IRQn);
buffer_descriptor_t *bd = _dcd.bdt[1][0];
@ -398,7 +403,7 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
const unsigned msk = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
NVIC_DisableIRQ(USB0_IRQn);
KHCI->ENDPOINT[epn].ENDPT &= ~msk;
CI_REG->ep[epn].endpt &= ~msk;
ep->max_packet_size = 0;
ep->length = 0;
ep->remaining = 0;
@ -446,7 +451,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
const unsigned epn = tu_edpt_number(ep_addr);
if (0 == epn) {
KHCI->ENDPOINT[epn].ENDPT |= USB_ENDPT_EPSTALL_MASK;
CI_REG->ep[epn].endpt |= USB_ENDPT_EPSTALL_MASK;
} else {
const unsigned dir = tu_edpt_dir(ep_addr);
const unsigned odd = _dcd.endpoint[epn][dir].odd;
@ -488,9 +493,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
bd[odd ^ 1].data = 1;
// We already cleared this in ISR, but just clear it here to be safe
const unsigned endpt = KHCI->ENDPOINT[epn].ENDPT;
const unsigned endpt = CI_REG->ep[epn].endpt;
if (endpt & USB_ENDPT_EPSTALL_MASK) {
KHCI->ENDPOINT[epn].ENDPT = endpt & ~USB_ENDPT_EPSTALL_MASK;
CI_REG->ep[epn].endpt = endpt & ~USB_ENDPT_EPSTALL_MASK;
}
if (ie) NVIC_EnableIRQ(USB0_IRQn);
@ -501,22 +506,22 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
//--------------------------------------------------------------------+
void dcd_int_handler(uint8_t rhport)
{
uint32_t is = KHCI->ISTAT;
uint32_t msk = KHCI->INTEN;
uint32_t is = CI_REG->int_stat;
uint32_t msk = CI_REG->int_en;
// clear non-enabled interrupts
KHCI->ISTAT = is & ~msk;
CI_REG->int_stat = is & ~msk;
is &= msk;
if (is & USB_ISTAT_ERROR_MASK) {
/* TODO: */
uint32_t es = KHCI->ERRSTAT;
KHCI->ERRSTAT = es;
KHCI->ISTAT = is; /* discard any pending events */
uint32_t es = CI_REG->err_stat;
CI_REG->err_stat = es;
CI_REG->int_stat = is; /* discard any pending events */
}
if (is & USB_ISTAT_USBRST_MASK) {
KHCI->ISTAT = is; /* discard any pending events */
CI_REG->int_stat = is; /* discard any pending events */
process_bus_reset(rhport);
}
@ -525,30 +530,30 @@ void dcd_int_handler(uint8_t rhport)
// Note Host usually has extra delay after bus reset (without SOF), which could falsely
// detected as Sleep event. Though usbd has debouncing logic so we are good
KHCI->ISTAT = USB_ISTAT_SLEEP_MASK;
CI_REG->int_stat = USB_ISTAT_SLEEP_MASK;
process_bus_sleep(rhport);
}
#if 0 // ISTAT_RESUME never trigger, probably for host mode ?
if (is & USB_ISTAT_RESUME_MASK) {
// TU_LOG2("ISTAT Resume: "); TU_LOG2_HEX(is);
KHCI->ISTAT = USB_ISTAT_RESUME_MASK;
CI_REG->int_stat = USB_ISTAT_RESUME_MASK;
process_bus_resume(rhport);
}
#endif
if (KHCI->USBTRC0 & USB_USBTRC0_USB_RESUME_INT_MASK) {
// TU_LOG2("USBTRC0 Resume: "); TU_LOG2_HEX(is); TU_LOG2_HEX(KHCI->USBTRC0);
if (CI_REG->usbtrc0 & USB_USBTRC0_USB_RESUME_INT_MASK) {
// TU_LOG2("USBTRC0 Resume: "); TU_LOG2_HEX(is); TU_LOG2_HEX(CI_REG->USBTRC0);
process_bus_resume(rhport);
}
if (is & USB_ISTAT_SOFTOK_MASK) {
KHCI->ISTAT = USB_ISTAT_SOFTOK_MASK;
CI_REG->int_stat = USB_ISTAT_SOFTOK_MASK;
dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
}
if (is & USB_ISTAT_STALL_MASK) {
KHCI->ISTAT = USB_ISTAT_STALL_MASK;
CI_REG->int_stat = USB_ISTAT_STALL_MASK;
process_stall(rhport);
}