mirror of https://github.com/ARMmbed/mbed-os.git
1517 lines
46 KiB
C++
1517 lines
46 KiB
C++
/* mbed Microcontroller Library
|
|
* Copyright (c) 2018-2018 ARM Limited, All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
* not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
|
|
#if defined(DEVICE_USBDEVICE) && DEVICE_USBDEVICE
|
|
|
|
extern "C"
|
|
{
|
|
#include "r_typedefs.h"
|
|
#include "iodefine.h"
|
|
}
|
|
#include "USBPhyHw.h"
|
|
#include "rza_io_regrw.h"
|
|
#include "USBDevice_Types.h"
|
|
#include "USBEndpoints_RZ_A1.h"
|
|
#include "USBPhy_RZ_A1_Def.h"
|
|
|
|
|
|
/**** User Selection ****/
|
|
#define USB_FUNCTION_CH 0
|
|
#define USB_FUNCTION_HISPEED 0 // 1: High-Speed 0: Full-Speed
|
|
|
|
#if (USB_FUNCTION_CH == 0)
|
|
#define USB_MX USB200
|
|
#define USBIX_IRQn USBI0_IRQn
|
|
#else
|
|
#define USB_MX USB201
|
|
#define USBIX_IRQn USBI1_IRQn
|
|
#endif
|
|
|
|
/* There are maintenance routine of SHTNAK and BFRE bits in original sample program.
|
|
* This sample is not programmed. Do maintenance the "def_pipecfg" array if you want it. */
|
|
const struct PIPECFGREC {
|
|
uint16_t endpoint;
|
|
uint16_t pipesel;
|
|
uint16_t pipecfg;
|
|
uint16_t pipebuf;
|
|
uint16_t pipemaxp;
|
|
uint16_t pipeperi;
|
|
} def_pipecfg[] = {
|
|
/* EP0OUT and EP0IN are configured by USB IP */
|
|
{
|
|
EP1OUT, /* EP1: Host -> Func, INT */
|
|
6 | USB_FUNCTION_D0FIFO_USE,
|
|
USB_TYPFIELD_INT | USB_BFREOFF | USB_CFG_DBLBOFF | USB_CFG_CNTMDON | USB_DIR_P_OUT | 1,
|
|
USB_BUF_SIZE(64) | 0x04u,
|
|
MAX_PACKET_SIZE_EP1,
|
|
3,
|
|
},
|
|
{
|
|
EP1IN, /* EP1: Host <- Func, INT */
|
|
7 | USB_FUNCTION_D1FIFO_USE,
|
|
USB_TYPFIELD_INT | USB_BFREOFF | USB_CFG_DBLBOFF | USB_CFG_CNTMDOFF | USB_DIR_P_IN | 1,
|
|
USB_BUF_SIZE(64) | 0x05u,
|
|
MAX_PACKET_SIZE_EP1,
|
|
3,
|
|
},
|
|
{
|
|
EP2OUT, /* EP2: Host -> Func, BULK */
|
|
3 | USB_FUNCTION_D0FIFO_USE,
|
|
USB_TYPFIELD_BULK | USB_BFREOFF | USB_CFG_DBLBON | USB_CFG_CNTMDON | USB_SHTNAKFIELD | USB_DIR_P_OUT | 2,
|
|
USB_BUF_SIZE(2048) | 0x30u,
|
|
MAX_PACKET_SIZE_EP2,
|
|
0,
|
|
},
|
|
{
|
|
EP2IN, /* EP2: Host <- Func, BULK */
|
|
4 | USB_FUNCTION_D1FIFO_USE,
|
|
USB_TYPFIELD_BULK | USB_BFREOFF | USB_CFG_DBLBOFF | USB_CFG_CNTMDON | USB_DIR_P_IN | 2,
|
|
USB_BUF_SIZE(2048) | 0x50u,
|
|
MAX_PACKET_SIZE_EP2,
|
|
0,
|
|
},
|
|
{
|
|
EP3OUT, /* EP3: Host -> Func, ISO */
|
|
1 | USB_FUNCTION_D0FIFO_USE,
|
|
USB_TYPFIELD_ISO | USB_BFREOFF | USB_CFG_DBLBON | USB_CFG_CNTMDOFF | USB_SHTNAKFIELD | USB_DIR_P_OUT | 3,
|
|
USB_BUF_SIZE(512) | 0x10u,
|
|
MAX_PACKET_SIZE_EP3,
|
|
0,
|
|
},
|
|
{
|
|
EP3IN, /* EP3: Host <- Func, ISO */
|
|
2 | USB_FUNCTION_D1FIFO_USE,
|
|
USB_TYPFIELD_ISO | USB_BFREOFF | USB_CFG_DBLBON | USB_CFG_CNTMDOFF | USB_DIR_P_IN | 3,
|
|
USB_BUF_SIZE(512) | 0x20u,
|
|
MAX_PACKET_SIZE_EP3,
|
|
0,
|
|
},
|
|
{ /* terminator */
|
|
0, 0, 0, 0, 0, 0
|
|
},
|
|
};
|
|
|
|
static USBPhyHw *instance;
|
|
static uint8_t _usb_speed = USB_FUNCTION_HISPEED;
|
|
static bool run_later_ctrl_comp = false;
|
|
|
|
USBPhy *get_usb_phy()
|
|
{
|
|
static USBPhyHw usbphy;
|
|
return &usbphy;
|
|
}
|
|
|
|
USBPhyHw::USBPhyHw(): events(NULL)
|
|
{
|
|
}
|
|
|
|
USBPhyHw::~USBPhyHw()
|
|
{
|
|
}
|
|
|
|
void USBPhyHw::init(USBPhyEvents *events)
|
|
{
|
|
volatile uint8_t dummy_read;
|
|
|
|
if (this->events == NULL) {
|
|
sleep_manager_lock_deep_sleep();
|
|
}
|
|
this->events = events;
|
|
|
|
/* registers me */
|
|
instance = this;
|
|
|
|
/* Disable IRQ */
|
|
GIC_DisableIRQ(USBIX_IRQn);
|
|
|
|
#if (USB_FUNCTION_CH == 0)
|
|
CPG.STBCR7 &= ~(CPG_STBCR7_MSTP71);
|
|
#else
|
|
CPG.STBCR7 &= ~(CPG_STBCR7_MSTP71 | CPG_STBCR7_MSTP70);
|
|
#endif
|
|
dummy_read = CPG.STBCR7;
|
|
(void)dummy_read;
|
|
|
|
/* module reset and clock select */
|
|
reset_usb(USB_X1_48MHZ); /* USB_X1 48MHz */
|
|
|
|
/* Set to USB Function and select speed */
|
|
USB_MX.SYSCFG0 &= ~USB_DPRPU;
|
|
USB_MX.SYSCFG0 &= ~USB_DRPD;
|
|
USB_MX.SYSCFG0 &= ~USB_DCFM; /* USB Functoin */
|
|
USB_MX.SYSCFG0 |= USB_USBE;
|
|
|
|
if (_usb_speed == 0) {
|
|
USB_MX.SYSCFG0 &= ~USB_HSE; /* Full-Speed */
|
|
} else {
|
|
USB_MX.SYSCFG0 |= USB_HSE; /* High-Speed */
|
|
}
|
|
cpu_delay_1us(1500);
|
|
}
|
|
|
|
void USBPhyHw::deinit()
|
|
{
|
|
volatile uint8_t dummy_read;
|
|
|
|
disconnect();
|
|
|
|
#if (USB_FUNCTION_CH == 0)
|
|
CPG.STBCR7 |= CPG_STBCR7_MSTP71;
|
|
#else
|
|
CPG.STBCR7 |= (CPG_STBCR7_MSTP71 | CPG_STBCR7_MSTP70);
|
|
#endif
|
|
dummy_read = CPG.STBCR7;
|
|
(void)dummy_read;
|
|
|
|
if (events != NULL) {
|
|
sleep_manager_unlock_deep_sleep();
|
|
}
|
|
events = NULL;
|
|
}
|
|
|
|
bool USBPhyHw::powered()
|
|
{
|
|
// return true if powered false otherwise. Devices which don't support
|
|
// this should always return true
|
|
return true;
|
|
}
|
|
|
|
void USBPhyHw::connect()
|
|
{
|
|
/* Enable pullup on D+ */
|
|
USB_MX.INTENB0 |= (USB_VBSE | USB_SOFE | USB_DVSE | USB_CTRE | USB_BEMPE | USB_NRDYE | USB_BRDYE);
|
|
USB_MX.SYSCFG0 |= USB_DPRPU;
|
|
|
|
/* Enable USB */
|
|
InterruptHandlerRegister(USBIX_IRQn, &_usbisr);
|
|
GIC_SetPriority(USBIX_IRQn, 16);
|
|
GIC_SetConfiguration(USBIX_IRQn, 1);
|
|
GIC_EnableIRQ(USBIX_IRQn);
|
|
}
|
|
|
|
void USBPhyHw::disconnect()
|
|
{
|
|
/* Disable USB */
|
|
GIC_DisableIRQ(USBIX_IRQn);
|
|
InterruptHandlerRegister(USBIX_IRQn, NULL);
|
|
|
|
/* Disable pullup on D+ */
|
|
USB_MX.SYSCFG0 &= ~USB_DPRPU;
|
|
cpu_delay_1us(1);
|
|
USB_MX.SYSCFG0 |= USB_DCFM;
|
|
cpu_delay_1us(1);
|
|
USB_MX.SYSCFG0 &= ~USB_DCFM;
|
|
}
|
|
|
|
void USBPhyHw::configure()
|
|
{
|
|
}
|
|
|
|
void USBPhyHw::unconfigure()
|
|
{
|
|
}
|
|
|
|
void USBPhyHw::sof_enable()
|
|
{
|
|
/* Enable SOF interrupt */
|
|
USB_MX.INTENB0 |= USB_SOFE;
|
|
}
|
|
|
|
void USBPhyHw::sof_disable()
|
|
{
|
|
/* Disable SOF interrupt */
|
|
USB_MX.INTENB0 &= ~USB_SOFE;
|
|
}
|
|
|
|
void USBPhyHw::set_address(uint8_t address)
|
|
{
|
|
if (address <= 127) {
|
|
set_pid(USB_PIPE0, USB_PID_BUF); /* Set BUF */
|
|
} else {
|
|
set_pid(USB_PIPE0, USB_PID_STALL); /* Not specification */
|
|
}
|
|
}
|
|
|
|
void USBPhyHw::remote_wakeup()
|
|
{
|
|
}
|
|
|
|
const usb_ep_table_t *USBPhyHw::endpoint_table()
|
|
{
|
|
static const usb_ep_table_t rza1_table = {
|
|
1, // No cost per endpoint - everything allocated up front
|
|
{
|
|
{USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0},
|
|
{USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0},
|
|
{USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0},
|
|
{USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
}
|
|
};
|
|
return &rza1_table;
|
|
}
|
|
|
|
uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet)
|
|
{
|
|
return MAX_PACKET_SIZE_EP0;
|
|
}
|
|
|
|
void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size)
|
|
{
|
|
memcpy(buffer, setup_buffer, size);
|
|
}
|
|
|
|
void USBPhyHw::ep0_read(uint8_t *data, uint32_t size)
|
|
{
|
|
pipe_ctrl[USB_PIPE0].req_size = size;
|
|
pipe_ctrl[USB_PIPE0].data_cnt = size;
|
|
pipe_ctrl[USB_PIPE0].p_data = data;
|
|
|
|
chg_curpipe(USB_PIPE0, USB_ISEL_READ); /* Switch FIFO and pipe number. */
|
|
USB_MX.CFIFOCTR = USB_BCLR; /* Buffer clear */
|
|
set_pid(USB_PIPE0, USB_PID_BUF); /* Set BUF */
|
|
USB_MX.BRDYENB |= (1 << USB_PIPE0); /* Enable ready interrupt */
|
|
USB_MX.NRDYENB |= (1 << USB_PIPE0); /* Enable not ready interrupt */
|
|
}
|
|
|
|
uint32_t USBPhyHw::ep0_read_result()
|
|
{
|
|
return pipe_ctrl[USB_PIPE0].req_size;
|
|
}
|
|
|
|
void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size)
|
|
{
|
|
if ((buffer == NULL) || (size == 0)) {
|
|
set_pid(USB_PIPE0, USB_PID_BUF); /* Set BUF */
|
|
return;
|
|
}
|
|
|
|
pipe_ctrl[USB_PIPE0].req_size = size;
|
|
pipe_ctrl[USB_PIPE0].data_cnt = size;
|
|
pipe_ctrl[USB_PIPE0].p_data = buffer;
|
|
|
|
chg_curpipe(USB_PIPE0, USB_ISEL_WRITE); /* Switch FIFO and pipe number. */
|
|
USB_MX.CFIFOCTR = USB_BCLR; /* Buffer clear */
|
|
/* Clear the PIPExBEMP status bit of the specified pipe to clear */
|
|
USB_MX.BEMPSTS = (uint16_t)((~(1 << USB_PIPE0)) & BEMPSTS_MASK);
|
|
|
|
/* Peripheral control sequence */
|
|
switch (write_data(USB_PIPE0)) {
|
|
case USB_WRITING : /* Continue of data write */
|
|
USB_MX.BRDYENB |= (1 << USB_PIPE0); /* Enable Ready interrupt */
|
|
USB_MX.NRDYENB |= (1 << USB_PIPE0); /* Enable Not Ready Interrupt */
|
|
set_pid(USB_PIPE0, USB_PID_BUF);
|
|
break;
|
|
case USB_WRITEEND : /* End of data write */
|
|
case USB_WRITESHRT : /* End of data write */
|
|
USB_MX.BEMPENB |= (1 << USB_PIPE0); /* Enable Empty Interrupt */
|
|
USB_MX.NRDYENB |= (1 << USB_PIPE0); /* Enable Not Ready Interrupt */
|
|
set_pid(USB_PIPE0, USB_PID_BUF);
|
|
break;
|
|
case USB_FIFOERROR : /* FIFO access error */
|
|
ctrl_end((uint16_t)USB_DATA_ERR);
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
}
|
|
|
|
void USBPhyHw::ep0_stall()
|
|
{
|
|
set_pid(USB_PIPE0, USB_PID_STALL);
|
|
run_later_ctrl_comp = false;
|
|
}
|
|
|
|
bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type)
|
|
{
|
|
const struct PIPECFGREC *cfg;
|
|
uint16_t pipe;
|
|
volatile uint16_t *p_reg;
|
|
|
|
if ((endpoint == EP0OUT) || (endpoint == EP0IN)) {
|
|
return true;
|
|
}
|
|
|
|
for (cfg = &def_pipecfg[0]; cfg->pipesel != 0; cfg++) {
|
|
if (cfg->endpoint == endpoint) {
|
|
break;
|
|
}
|
|
}
|
|
if (cfg->pipesel == 0) {
|
|
return false;
|
|
}
|
|
|
|
pipe = (cfg->pipesel & USB_CURPIPE);
|
|
|
|
/* Interrupt Disable */
|
|
USB_MX.BRDYENB &= (~(1 << pipe)); /* Disable Ready Interrupt */
|
|
USB_MX.NRDYENB &= (~(1 << pipe)); /* Disable Not Ready Interrupt */
|
|
USB_MX.BEMPENB &= (~(1 << pipe)); /* Disable Empty Interrupt */
|
|
|
|
set_pid(pipe, USB_PID_NAK);
|
|
|
|
/* CurrentPIPE Clear */
|
|
if ((USB_MX.CFIFOSEL & USB_CURPIPE) == pipe) {
|
|
USB_MX.CFIFOSEL &= ~USB_CURPIPE;
|
|
}
|
|
if ((USB_MX.D0FIFOSEL & USB_CURPIPE) == pipe) {
|
|
USB_MX.D0FIFOSEL &= ~USB_CURPIPE;
|
|
}
|
|
if ((USB_MX.D1FIFOSEL & USB_CURPIPE) == pipe) {
|
|
USB_MX.D1FIFOSEL &= ~USB_CURPIPE;
|
|
}
|
|
|
|
/* PIPE Configuration */
|
|
USB_MX.PIPESEL = pipe; /* Pipe select */
|
|
USB_MX.PIPECFG = cfg->pipecfg;
|
|
USB_MX.PIPEBUF = cfg->pipebuf;
|
|
USB_MX.PIPEMAXP = cfg->pipemaxp;
|
|
USB_MX.PIPEPERI = cfg->pipeperi;
|
|
|
|
p_reg = get_pipectr_reg(pipe);
|
|
/* Set toggle bit to DATA0 */
|
|
*p_reg |= USB_SQCLR;
|
|
/* Buffer Clear */
|
|
*p_reg |= USB_ACLRM;
|
|
*p_reg &= ~USB_ACLRM;
|
|
|
|
return true;
|
|
}
|
|
|
|
void USBPhyHw::endpoint_remove(usb_ep_t endpoint)
|
|
{
|
|
uint16_t pipe = EP2PIPE(endpoint);
|
|
|
|
/* Interrupt Disable */
|
|
USB_MX.BRDYENB &= (~(1 << pipe)); /* Disable Ready Interrupt */
|
|
USB_MX.NRDYENB &= (~(1 << pipe)); /* Disable Not Ready Interrupt */
|
|
USB_MX.BEMPENB &= (~(1 << pipe)); /* Disable Empty Interrupt */
|
|
|
|
set_pid(pipe, USB_PID_NAK);
|
|
|
|
/* CurrentPIPE Clear */
|
|
if ((USB_MX.CFIFOSEL & USB_CURPIPE) == pipe) {
|
|
USB_MX.CFIFOSEL &= ~USB_CURPIPE;
|
|
}
|
|
if ((USB_MX.D0FIFOSEL & USB_CURPIPE) == pipe) {
|
|
USB_MX.D0FIFOSEL &= ~USB_CURPIPE;
|
|
}
|
|
if ((USB_MX.D1FIFOSEL & USB_CURPIPE) == pipe) {
|
|
USB_MX.D1FIFOSEL &= ~USB_CURPIPE;
|
|
}
|
|
|
|
/* PIPE Configuration */
|
|
USB_MX.PIPESEL = pipe; /* Pipe select */
|
|
USB_MX.PIPECFG = 0;
|
|
|
|
pipe_ctrl[pipe].enable = false;
|
|
pipe_ctrl[pipe].status = USB_DATA_NONE;
|
|
}
|
|
|
|
void USBPhyHw::endpoint_stall(usb_ep_t endpoint)
|
|
{
|
|
uint16_t pipe = EP2PIPE(endpoint);
|
|
|
|
set_pid(pipe, USB_PID_STALL);
|
|
|
|
pipe_ctrl[pipe].enable = false;
|
|
pipe_ctrl[pipe].status = USB_DATA_STALL;
|
|
}
|
|
|
|
void USBPhyHw::endpoint_unstall(usb_ep_t endpoint)
|
|
{
|
|
uint16_t pipe = EP2PIPE(endpoint);
|
|
volatile uint16_t *p_reg;
|
|
|
|
set_pid(pipe, USB_PID_NAK);
|
|
|
|
p_reg = get_pipectr_reg(pipe);
|
|
/* Set toggle bit to DATA0 */
|
|
*p_reg |= USB_SQCLR;
|
|
/* Buffer Clear */
|
|
*p_reg |= USB_ACLRM;
|
|
*p_reg &= ~USB_ACLRM;
|
|
|
|
pipe_ctrl[pipe].enable = false;
|
|
pipe_ctrl[pipe].status = USB_DATA_NONE;
|
|
}
|
|
|
|
bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size)
|
|
{
|
|
uint16_t mxps;
|
|
uint16_t trncnt;
|
|
volatile uint16_t *p_reg;
|
|
uint16_t pipe = EP2PIPE(endpoint);
|
|
|
|
if (pipe_ctrl[pipe].status == USB_DATA_STALL) {
|
|
return false;
|
|
}
|
|
|
|
pipe_ctrl[pipe].status = USB_DATA_READING;
|
|
pipe_ctrl[pipe].req_size = size;
|
|
pipe_ctrl[pipe].data_cnt = size;
|
|
pipe_ctrl[pipe].p_data = data;
|
|
pipe_ctrl[pipe].enable = true;
|
|
|
|
set_pid(pipe, USB_PID_NAK); /* Set NAK */
|
|
|
|
USB_MX.BEMPSTS = (uint16_t)((~(1 << pipe)) & BEMPSTS_MASK); /* BEMP Status Clear */
|
|
USB_MX.BRDYSTS = (uint16_t)((~(1 << pipe)) & BRDYSTS_MASK); /* BRDY Status Clear */
|
|
USB_MX.NRDYSTS = (uint16_t)((~(1 << pipe)) & NRDYSTS_MASK); /* NRDY Status Clear */
|
|
|
|
chg_curpipe(pipe, USB_ISEL_READ); /* Switch FIFO and pipe number. */
|
|
p_reg = get_fifoctr_reg(pipe);
|
|
*p_reg = USB_BCLR; /* Clear BCLR */
|
|
|
|
if (size != 0) {
|
|
/* Max Packet Size */
|
|
USB_MX.PIPESEL = pipe; /* Pipe select */
|
|
mxps = (uint16_t)(USB_MX.PIPEMAXP & USB_MXPS);
|
|
/* Data size check */
|
|
if ((size % mxps) == (uint32_t)0u) {
|
|
trncnt = (uint16_t)(size / mxps);
|
|
} else {
|
|
trncnt = (uint16_t)((size / mxps) + (uint32_t)1u);
|
|
}
|
|
|
|
/* Set Transaction counter */
|
|
p_reg = get_pipetre_reg(pipe);
|
|
if (p_reg != NULL) {
|
|
*p_reg |= USB_TRCLR;
|
|
}
|
|
p_reg = get_pipetrn_reg(pipe);
|
|
if (p_reg != NULL) {
|
|
*p_reg = trncnt;
|
|
}
|
|
p_reg = get_pipetre_reg(pipe);
|
|
if (p_reg != NULL) {
|
|
*p_reg |= USB_TRENB;
|
|
}
|
|
|
|
p_reg = get_pipectr_reg(pipe);
|
|
/* Buffer Clear */
|
|
*p_reg |= USB_ACLRM;
|
|
*p_reg &= ~USB_ACLRM;
|
|
}
|
|
|
|
set_pid(pipe, USB_PID_BUF); /* Set BUF */
|
|
USB_MX.BRDYENB |= (1 << pipe); /* Enable Ready Interrupt */
|
|
USB_MX.NRDYENB |= (1 << pipe); /* Enable Not Ready Interrupt */
|
|
|
|
return true;
|
|
}
|
|
|
|
uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint)
|
|
{
|
|
uint16_t pipe = EP2PIPE(endpoint);
|
|
|
|
return pipe_ctrl[pipe].req_size;
|
|
}
|
|
|
|
bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
uint16_t pipe = EP2PIPE(endpoint);
|
|
|
|
if (pipe_ctrl[pipe].status == USB_DATA_STALL) {
|
|
return false;
|
|
}
|
|
|
|
pipe_ctrl[pipe].status = USB_DATA_WRITING;
|
|
pipe_ctrl[pipe].req_size = size;
|
|
pipe_ctrl[pipe].data_cnt = size;
|
|
pipe_ctrl[pipe].p_data = data;
|
|
pipe_ctrl[pipe].enable = true;
|
|
|
|
set_pid(pipe, USB_PID_NAK); /* Set NAK */
|
|
|
|
USB_MX.BEMPSTS = (uint16_t)((~(1 << pipe)) & BEMPSTS_MASK); /* BEMP Status Clear */
|
|
USB_MX.BRDYSTS = (uint16_t)((~(1 << pipe)) & BRDYSTS_MASK); /* BRDY Status Clear */
|
|
USB_MX.NRDYSTS = (uint16_t)((~(1 << pipe)) & NRDYSTS_MASK); /* NRDY Status Clear */
|
|
|
|
p_reg = get_pipectr_reg(pipe);
|
|
/* Buffer Clear */
|
|
*p_reg |= USB_ACLRM;
|
|
*p_reg &= ~USB_ACLRM;
|
|
|
|
buf_to_fifo(pipe); /* Buffer to FIFO data write */
|
|
set_pid(pipe, USB_PID_BUF); /* Set BUF */
|
|
|
|
return true;
|
|
}
|
|
|
|
void USBPhyHw::endpoint_abort(usb_ep_t endpoint)
|
|
{
|
|
forced_termination(EP2PIPE(endpoint), (uint16_t)USB_DATA_NONE);
|
|
}
|
|
|
|
void USBPhyHw::process()
|
|
{
|
|
/* Register Save */
|
|
uint16_t intsts0 = USB_MX.INTSTS0;
|
|
uint16_t brdysts = USB_MX.BRDYSTS;
|
|
uint16_t nrdysts = USB_MX.NRDYSTS;
|
|
uint16_t bempsts = USB_MX.BEMPSTS;
|
|
uint16_t intenb0 = USB_MX.INTENB0;
|
|
uint16_t brdyenb = USB_MX.BRDYENB;
|
|
uint16_t nrdyenb = USB_MX.NRDYENB;
|
|
uint16_t bempenb = USB_MX.BEMPENB;
|
|
|
|
/* Interrupt status get */
|
|
uint16_t ists0 = (uint16_t)(intsts0 & intenb0);
|
|
uint16_t bsts = (uint16_t)(brdysts & brdyenb);
|
|
uint16_t nsts = (uint16_t)(nrdysts & nrdyenb);
|
|
uint16_t ests = (uint16_t)(bempsts & bempenb);
|
|
|
|
uint16_t i;
|
|
|
|
if ((intsts0 & (USB_VBINT | USB_RESM | USB_SOFR | USB_DVST |
|
|
USB_CTRT | USB_BEMP | USB_NRDY | USB_BRDY)) == 0u) {
|
|
return;
|
|
}
|
|
|
|
/***** Processing USB bus signal *****/
|
|
/***** Resume signal *****/
|
|
if ((ists0 & USB_RESM) == USB_RESM) {
|
|
USB_MX.INTSTS0 = (uint16_t)~USB_RESM;
|
|
USB_MX.INTENB0 &= (~USB_RSME); /* RESM interrupt disable */
|
|
events->suspend(true);
|
|
}
|
|
|
|
/***** Vbus change *****/
|
|
else if ((ists0 & USB_VBINT) == USB_VBINT) {
|
|
USB_MX.INTSTS0 = (uint16_t)~USB_VBINT;
|
|
if (chk_vbsts()) {
|
|
/* USB attach */
|
|
/* Non processing. */
|
|
} else {
|
|
/* USB detach */
|
|
for (i = USB_MIN_PIPE_NO; i < PIPE_NUM; i++) {
|
|
if (pipe_ctrl[i].enable) {
|
|
forced_termination(i, (uint16_t)USB_DATA_NONE);
|
|
}
|
|
}
|
|
USB_MX.INTSTS0 = 0;
|
|
USB_MX.BRDYSTS = 0;
|
|
USB_MX.NRDYSTS = 0;
|
|
USB_MX.BEMPSTS = 0;
|
|
USB_MX.BRDYENB = 0;
|
|
USB_MX.NRDYENB = 0;
|
|
USB_MX.BEMPENB = 0;
|
|
}
|
|
}
|
|
|
|
/***** SOFR change *****/
|
|
else if ((ists0 & USB_SOFR) == USB_SOFR) {
|
|
USB_MX.INTSTS0 = (uint16_t)~USB_SOFR;
|
|
events->sof(USB_MX.FRMNUM & USB_FRNM);
|
|
}
|
|
|
|
/***** Processing device state *****/
|
|
/***** DVST change *****/
|
|
else if ((ists0 & USB_DVST) == USB_DVST) {
|
|
USB_MX.INTSTS0 = (uint16_t)~USB_DVST;
|
|
|
|
switch ((uint16_t)(intsts0 & USB_DVSQ)) {
|
|
case USB_DS_POWR :
|
|
break;
|
|
case USB_DS_DFLT :
|
|
USB_MX.DCPCFG = 0; /* DCP configuration register (0x5C) */
|
|
USB_MX.DCPMAXP = MAX_PACKET_SIZE_EP0; /* DCP maxpacket size register (0x5E) */
|
|
|
|
events->reset();
|
|
break;
|
|
case USB_DS_ADDS :
|
|
break;
|
|
case USB_DS_CNFG :
|
|
break;
|
|
case USB_DS_SPD_POWR :
|
|
case USB_DS_SPD_DFLT :
|
|
case USB_DS_SPD_ADDR :
|
|
case USB_DS_SPD_CNFG :
|
|
events->suspend(false);
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***** Processing PIPE0 data *****/
|
|
else if (((ists0 & USB_BRDY) == USB_BRDY) && ((bsts & USB_BRDY0) == USB_BRDY0)) {
|
|
/* ==== BRDY PIPE0 ==== */
|
|
USB_MX.BRDYSTS = (uint16_t)((~USB_BRDY0) & BRDYSTS_MASK);
|
|
|
|
/* When operating by the peripheral function, usb_brdy_pipe() is executed with PIPEx request because */
|
|
/* two BRDY messages are issued even when the demand of PIPE0 and PIPEx has been generated at the same time. */
|
|
if ((USB_MX.CFIFOSEL & USB_ISEL_WRITE) == USB_ISEL_WRITE) {
|
|
switch (write_data(USB_PIPE0)) {
|
|
case USB_WRITEEND :
|
|
case USB_WRITESHRT :
|
|
USB_MX.BRDYENB &= (~(1 << USB_PIPE0));
|
|
break;
|
|
case USB_WRITING :
|
|
set_pid(USB_PIPE0, USB_PID_BUF);
|
|
break;
|
|
case USB_FIFOERROR :
|
|
ctrl_end((uint16_t)USB_DATA_ERR);
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
events->ep0_in();
|
|
} else {
|
|
switch (read_data(USB_PIPE0)) {
|
|
case USB_READEND :
|
|
case USB_READSHRT :
|
|
USB_MX.BRDYENB &= (~(1 << USB_PIPE0));
|
|
pipe_ctrl[USB_PIPE0].req_size -= pipe_ctrl[USB_PIPE0].data_cnt;
|
|
break;
|
|
case USB_READING :
|
|
set_pid(USB_PIPE0, USB_PID_BUF);
|
|
break;
|
|
case USB_READOVER :
|
|
ctrl_end((uint16_t)USB_DATA_OVR);
|
|
pipe_ctrl[USB_PIPE0].req_size -= pipe_ctrl[USB_PIPE0].data_cnt;
|
|
break;
|
|
case USB_FIFOERROR :
|
|
ctrl_end((uint16_t)USB_DATA_ERR);
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
events->ep0_out();
|
|
}
|
|
} else if (((ists0 & USB_BEMP) == USB_BEMP) && ((ests & USB_BEMP0) == USB_BEMP0)) {
|
|
/* ==== BEMP PIPE0 ==== */
|
|
USB_MX.BEMPSTS = (uint16_t)((~USB_BEMP0) & BEMPSTS_MASK);
|
|
|
|
events->ep0_in();
|
|
} else if (((ists0 & USB_NRDY) == USB_NRDY) && ((nsts & USB_NRDY0) == USB_NRDY0)) {
|
|
/* ==== NRDY PIPE0 ==== */
|
|
USB_MX.NRDYSTS = (uint16_t)((~USB_NRDY0) & NRDYSTS_MASK);
|
|
/* Non processing. */
|
|
}
|
|
|
|
/***** Processing setup transaction *****/
|
|
else if ((ists0 & USB_CTRT) == USB_CTRT) {
|
|
USB_MX.INTSTS0 = (uint16_t)~USB_CTRT;
|
|
|
|
/* CTSQ bit changes later than CTRT bit for ASSP. */
|
|
/* CTSQ reloading */
|
|
uint16_t stginfo = (uint16_t)(intsts0 & USB_CTSQ);
|
|
if (stginfo != USB_CS_IDST) {
|
|
if (((USB_CS_RDDS == stginfo) || (USB_CS_WRDS == stginfo)) || (USB_CS_WRND == stginfo)) {
|
|
/* Save request register */
|
|
uint16_t *bufO = &setup_buffer[0];
|
|
|
|
USB_MX.INTSTS0 = (uint16_t)~USB_VALID;
|
|
*bufO++ = USB_MX.USBREQ; /* data[0] <= bmRequest, data[1] <= bmRequestType */
|
|
*bufO++ = USB_MX.USBVAL; /* data[2] data[3] <= wValue */
|
|
*bufO++ = USB_MX.USBINDX; /* data[4] data[5] <= wIndex */
|
|
*bufO++ = USB_MX.USBLENG; /* data[6] data[7] <= wLength */
|
|
}
|
|
}
|
|
|
|
/* Switch on the control transfer stage (CTSQ). */
|
|
switch (stginfo) {
|
|
case USB_CS_IDST : /* Idle or setup stage */
|
|
break;
|
|
case USB_CS_RDDS : /* Control read data stage */
|
|
events->ep0_setup();
|
|
break;
|
|
case USB_CS_WRDS : /* Control write data stage */
|
|
events->ep0_setup();
|
|
break;
|
|
case USB_CS_WRND : /* Status stage of a control write where there is no data stage. */
|
|
events->ep0_setup();
|
|
run_later_ctrl_comp = true;
|
|
break;
|
|
case USB_CS_RDSS : /* Control read status stage */
|
|
USB_MX.DCPCTR |= USB_CCPL;
|
|
break;
|
|
case USB_CS_WRSS : /* Control write status stage */
|
|
USB_MX.DCPCTR |= USB_CCPL;
|
|
break;
|
|
case USB_CS_SQER : /* Control sequence error */
|
|
default : /* Illegal */
|
|
ctrl_end((uint16_t)USB_DATA_ERR);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***** Processing PIPE1-MAX_PIPE_NO data *****/
|
|
else if ((ists0 & USB_BRDY) == USB_BRDY) {
|
|
/* ==== BRDY PIPEx ==== */
|
|
USB_MX.BRDYSTS = (uint16_t)((~bsts) & BRDYSTS_MASK);
|
|
|
|
for (i = USB_MIN_PIPE_NO; i < PIPE_NUM; i++) {
|
|
if ((bsts & USB_BITSET(i)) != 0u) {
|
|
/* Interrupt check */
|
|
if (pipe_ctrl[i].enable) {
|
|
USB_MX.PIPESEL = i;
|
|
if (USB_BUF2FIFO == (uint16_t)(USB_MX.PIPECFG & USB_DIRFIELD)) {
|
|
/* write */
|
|
buf_to_fifo(i); /* Buffer to FIFO data write */
|
|
events->in(PIPE2EP(i));
|
|
} else {
|
|
/* read */
|
|
fifo_to_buf(i); /* FIFO to Buffer data read */
|
|
events->out(PIPE2EP(i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if ((ists0 & USB_BEMP) == USB_BEMP) {
|
|
/* ==== BEMP PIPEx ==== */
|
|
USB_MX.BEMPSTS = (uint16_t)((~ests) & BEMPSTS_MASK);
|
|
|
|
for (i = USB_MIN_PIPE_NO; i < PIPE_NUM; i++) {
|
|
if ((ests & USB_BITSET(i)) != 0) {
|
|
/* Interrupt check */
|
|
if (pipe_ctrl[i].enable) {
|
|
/* MAX packet size error ? */
|
|
if (((get_pid(i) & USB_PID_STALL) == USB_PID_STALL) || ((get_pid(i) & USB_PID_STALL2) == USB_PID_STALL2)) {
|
|
forced_termination(i, (uint16_t)USB_DATA_STALL);
|
|
} else {
|
|
if ((i >= USB_PIPE6) || ((*get_pipectr_reg(i) & USB_INBUFM) != USB_INBUFM)) {
|
|
data_end(i, (uint16_t)USB_DATA_NONE); /* End of data transfer */
|
|
} else {
|
|
USB_MX.BEMPENB |= (1 << i);
|
|
}
|
|
}
|
|
events->in(PIPE2EP(i));
|
|
}
|
|
}
|
|
}
|
|
} else if ((ists0 & USB_NRDY) == USB_NRDY) {
|
|
/* ==== NRDY PIPEx ==== */
|
|
USB_MX.NRDYSTS = (uint16_t)((~nsts) & NRDYSTS_MASK);
|
|
|
|
for (i = USB_MIN_PIPE_NO; i < PIPE_NUM; i++) {
|
|
if ((nsts & USB_BITSET(i)) != 0) {
|
|
/* Interrupt check */
|
|
if (pipe_ctrl[i].enable) {
|
|
if (((get_pid(i) & USB_PID_STALL) != USB_PID_STALL) && ((get_pid(i) & USB_PID_STALL2) != USB_PID_STALL2)) {
|
|
set_pid(i, USB_PID_BUF);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/* Non processing. */
|
|
}
|
|
}
|
|
|
|
void USBPhyHw::_usbisr(void)
|
|
{
|
|
GIC_DisableIRQ(USBIX_IRQn);
|
|
|
|
run_later_ctrl_comp = false;
|
|
|
|
instance->events->start_process();
|
|
|
|
if (run_later_ctrl_comp) {
|
|
USB_MX.DCPCTR &= (~USB_PID);
|
|
USB_MX.DCPCTR |= USB_PID_BUF;
|
|
|
|
USB_MX.DCPCTR |= USB_CCPL;
|
|
}
|
|
|
|
/* Re-enable interrupt */
|
|
GIC_ClearPendingIRQ(USBIX_IRQn);
|
|
GIC_EnableIRQ(USBIX_IRQn);
|
|
}
|
|
|
|
void USBPhyHw::chg_curpipe(uint16_t pipe, uint16_t isel)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
uint16_t fifo_use;
|
|
uint16_t isel_val;
|
|
uint16_t buf;
|
|
|
|
fifo_use = PIPE2FIFO(pipe);
|
|
if ((fifo_use == USB_FUNCTION_D0FIFO_USE) || (fifo_use == USB_FUNCTION_D1FIFO_USE)) {
|
|
isel_val = 0;
|
|
} else {
|
|
isel_val = isel;
|
|
}
|
|
|
|
p_reg = get_fifosel_reg(pipe);
|
|
buf = *p_reg;
|
|
buf &= (uint16_t)(~(USB_RCNT | USB_ISEL | USB_CURPIPE | USB_MBW));
|
|
buf |= (uint16_t)((USB_RCNT | isel_val | pipe | USB_MBW_32) & (USB_RCNT | USB_ISEL | USB_CURPIPE | USB_MBW));
|
|
*p_reg = buf;
|
|
|
|
do {
|
|
cpu_delay_1us(1);
|
|
buf = *p_reg;
|
|
} while ((buf & (uint16_t)(USB_ISEL | USB_CURPIPE)) != (uint16_t)(isel_val | pipe));
|
|
}
|
|
|
|
uint16_t USBPhyHw::is_set_frdy(uint16_t pipe, uint16_t isel)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
uint16_t buffer;
|
|
int retry_cnt = 0;
|
|
|
|
chg_curpipe(pipe, isel); /* Changes the FIFO port by the pipe. */
|
|
p_reg = get_fifoctr_reg(pipe);
|
|
for (retry_cnt = 0; retry_cnt < 10; retry_cnt++) {
|
|
buffer = *p_reg;
|
|
if ((uint16_t)(buffer & USB_FRDY) == USB_FRDY) {
|
|
return (buffer);
|
|
}
|
|
cpu_delay_1us(1);
|
|
}
|
|
|
|
return (USB_FIFOERROR);
|
|
}
|
|
|
|
uint8_t *USBPhyHw::read_fifo(uint16_t pipe, uint16_t count, uint8_t *read_p)
|
|
{
|
|
iodefine_reg32_t *p_reg;
|
|
uint16_t even;
|
|
uint16_t odd;
|
|
uint32_t odd_byte_data_temp;
|
|
|
|
p_reg = (iodefine_reg32_t *)get_fifo_reg(pipe);
|
|
for (even = (uint16_t)(count >> 2); (even != 0); --even) {
|
|
/* 32bit FIFO access */
|
|
*((uint32_t *)read_p) = p_reg->UINT32;
|
|
read_p += sizeof(uint32_t);
|
|
}
|
|
odd = count % 4;
|
|
if (count < 4) {
|
|
odd = count;
|
|
}
|
|
if (odd != 0) {
|
|
/* 32bit FIFO access */
|
|
odd_byte_data_temp = p_reg->UINT32;
|
|
/* Condition compilation by the difference of the endian */
|
|
do {
|
|
*read_p = (uint8_t)(odd_byte_data_temp & 0x000000ff);
|
|
odd_byte_data_temp = odd_byte_data_temp >> 8;
|
|
/* Renewal read pointer */
|
|
read_p += sizeof(uint8_t);
|
|
odd--;
|
|
} while (odd != 0);
|
|
}
|
|
|
|
return read_p;
|
|
}
|
|
|
|
uint16_t USBPhyHw::read_data(uint16_t pipe)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
uint16_t count;
|
|
uint16_t buffer;
|
|
uint16_t mxps;
|
|
uint16_t dtln;
|
|
uint16_t end_flag;
|
|
|
|
/* Changes FIFO port by the pipe. */
|
|
buffer = is_set_frdy(pipe, 0);
|
|
if (buffer == USB_FIFOERROR) {
|
|
return (USB_FIFOERROR); /* FIFO access error */
|
|
}
|
|
dtln = (uint16_t)(buffer & USB_DTLN);
|
|
|
|
/* Max Packet Size */
|
|
if (pipe == USB_PIPE0) {
|
|
mxps = (uint16_t)(USB_MX.DCPMAXP & USB_MAXP);
|
|
} else {
|
|
USB_MX.PIPESEL = pipe; /* Pipe select */
|
|
mxps = (uint16_t)(USB_MX.PIPEMAXP & USB_MXPS);
|
|
}
|
|
|
|
if (pipe_ctrl[pipe].data_cnt < dtln) {
|
|
/* Buffer Over ? */
|
|
end_flag = USB_READOVER;
|
|
set_pid(pipe, USB_PID_NAK); /* Set NAK */
|
|
count = (uint16_t)pipe_ctrl[pipe].data_cnt;
|
|
pipe_ctrl[pipe].data_cnt = dtln;
|
|
} else if (pipe_ctrl[pipe].data_cnt == dtln) {
|
|
/* Just Receive Size */
|
|
count = dtln;
|
|
if ((count == 0) || ((dtln % mxps) != 0)) {
|
|
/* Just Receive Size */
|
|
/* Peripheral Function */
|
|
end_flag = USB_READSHRT;
|
|
} else {
|
|
end_flag = USB_READEND;
|
|
set_pid(pipe, USB_PID_NAK); /* Set NAK */
|
|
}
|
|
} else {
|
|
/* Continuous Receive data */
|
|
count = dtln;
|
|
end_flag = USB_READING;
|
|
if (count == 0) {
|
|
/* Null Packet receive */
|
|
end_flag = USB_READSHRT;
|
|
set_pid(pipe, USB_PID_NAK); /* Set NAK */
|
|
}
|
|
if ((count % mxps) != 0) {
|
|
/* Null Packet receive */
|
|
end_flag = USB_READSHRT;
|
|
set_pid(pipe, USB_PID_NAK); /* Set NAK */
|
|
}
|
|
}
|
|
|
|
if (dtln == 0) { /* 0 length packet */
|
|
p_reg = get_fifoctr_reg(pipe);
|
|
*p_reg = USB_BCLR; /* Clear BCLR */
|
|
} else {
|
|
pipe_ctrl[pipe].p_data = read_fifo(pipe, count, pipe_ctrl[pipe].p_data);
|
|
}
|
|
pipe_ctrl[pipe].data_cnt -= count;
|
|
|
|
return end_flag;
|
|
}
|
|
|
|
void USBPhyHw::fifo_to_buf(uint16_t pipe)
|
|
{
|
|
/* Check FIFO access sequence */
|
|
switch (read_data(pipe)) {
|
|
case USB_READING : /* Continue of data read */
|
|
break;
|
|
case USB_READEND : /* End of data read */
|
|
data_end(pipe, (uint16_t)USB_DATA_OK);
|
|
pipe_ctrl[pipe].req_size -= pipe_ctrl[pipe].data_cnt;
|
|
break;
|
|
case USB_READSHRT : /* End of data read */
|
|
data_end(pipe, (uint16_t)USB_DATA_SHT);
|
|
pipe_ctrl[pipe].req_size -= pipe_ctrl[pipe].data_cnt;
|
|
break;
|
|
case USB_READOVER : /* Buffer over */
|
|
forced_termination(pipe, (uint16_t)USB_DATA_OVR);
|
|
pipe_ctrl[pipe].req_size -= pipe_ctrl[pipe].data_cnt;
|
|
break;
|
|
case USB_FIFOERROR : /* FIFO access error */
|
|
default:
|
|
forced_termination(pipe, (uint16_t)USB_DATA_ERR);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint8_t *USBPhyHw::write_fifo(uint16_t pipe, uint16_t count, uint8_t *write_p)
|
|
{
|
|
iodefine_reg32_t *p_reg;
|
|
uint16_t even;
|
|
uint16_t odd;
|
|
|
|
p_reg = (iodefine_reg32_t *)get_fifo_reg(pipe);
|
|
set_mbw(pipe, USB_MBW_32); /* 32bit access */
|
|
for (even = (uint16_t)(count >> 2); (even != 0); --even) {
|
|
p_reg->UINT32 = *((uint32_t *)write_p);
|
|
write_p += sizeof(uint32_t);
|
|
}
|
|
odd = count % 4;
|
|
if (count < 4) {
|
|
odd = count;
|
|
}
|
|
if ((odd & (uint16_t)0x0002u) != 0u) {
|
|
set_mbw(pipe, USB_MBW_16); /* 16bit access */
|
|
p_reg->UINT16[H] = *((uint16_t *)write_p);
|
|
write_p += sizeof(uint16_t);
|
|
}
|
|
if ((odd & (uint16_t)0x0001u) != 0u) {
|
|
set_mbw(pipe, USB_MBW_8); /* 8bit access */
|
|
p_reg->UINT8[HH] = *write_p;
|
|
write_p++;
|
|
}
|
|
|
|
return write_p;
|
|
}
|
|
|
|
uint16_t USBPhyHw::write_data(uint16_t pipe)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
uint16_t size;
|
|
uint16_t count;
|
|
uint16_t mxps;
|
|
uint16_t end_flag;
|
|
uint16_t buffer;
|
|
|
|
/* Changes FIFO port by the pipe. */
|
|
if (pipe == USB_PIPE0) {
|
|
buffer = is_set_frdy(pipe, USB_ISEL_WRITE);
|
|
} else {
|
|
buffer = is_set_frdy(pipe, 0);
|
|
}
|
|
|
|
if (buffer == USB_FIFOERROR) {
|
|
return (USB_FIFOERROR);
|
|
}
|
|
|
|
if (pipe == USB_PIPE0) {
|
|
/* Max Packet Size */
|
|
mxps = (uint16_t)(USB_MX.DCPMAXP & USB_MAXP);
|
|
|
|
/* Data buffer size */
|
|
if ((USB_MX.DCPCFG & USB_CNTMDFIELD) == USB_CFG_CNTMDON) {
|
|
size = USB_PIPE0BUF;
|
|
} else {
|
|
size = mxps;
|
|
}
|
|
} else {
|
|
/* Max Packet Size */
|
|
USB_MX.PIPESEL = pipe; /* Pipe select */
|
|
mxps = (uint16_t)(USB_MX.PIPEMAXP & USB_MXPS);
|
|
|
|
/* Data buffer size */
|
|
if ((USB_MX.PIPECFG & USB_CNTMDFIELD) == USB_CFG_CNTMDON) {
|
|
size = (uint16_t)((uint16_t)((USB_MX.PIPEBUF >> USB_BUFSIZE_BIT) + 1) * USB_PIPEXBUF);
|
|
} else {
|
|
size = mxps;
|
|
}
|
|
}
|
|
|
|
/* Data size check */
|
|
if (pipe_ctrl[pipe].data_cnt <= (uint32_t)size) {
|
|
count = (uint16_t)pipe_ctrl[pipe].data_cnt;
|
|
if (count == 0) {
|
|
end_flag = USB_WRITESHRT; /* Null Packet is end of write */
|
|
} else if ((count % mxps) != 0) {
|
|
end_flag = USB_WRITESHRT; /* Short Packet is end of write */
|
|
} else {
|
|
end_flag = USB_WRITEEND; /* Just Send Size */
|
|
}
|
|
} else {
|
|
/* Write continues */
|
|
end_flag = USB_WRITING;
|
|
count = size;
|
|
}
|
|
|
|
pipe_ctrl[pipe].p_data = write_fifo(pipe, count, pipe_ctrl[pipe].p_data);
|
|
|
|
/* Check data count to remain */
|
|
if (pipe_ctrl[pipe].data_cnt < (uint32_t)size) {
|
|
pipe_ctrl[pipe].data_cnt = 0u; /* Clear data count */
|
|
|
|
p_reg = get_fifoctr_reg(pipe);
|
|
if ((*p_reg & USB_BVAL) == 0u) { /* Check BVAL */
|
|
*p_reg |= USB_BVAL; /* Short Packet */
|
|
}
|
|
} else {
|
|
pipe_ctrl[pipe].data_cnt -= count; /* Total data count - count */
|
|
}
|
|
|
|
return end_flag;
|
|
}
|
|
|
|
void USBPhyHw::buf_to_fifo(uint16_t pipe)
|
|
{
|
|
/* Disable Ready Interrupt */
|
|
USB_MX.BRDYENB &= (~(1 << pipe));
|
|
|
|
/* Peripheral control sequence */
|
|
switch (write_data(pipe)) {
|
|
case USB_WRITING : /* Continue of data write */
|
|
USB_MX.BRDYENB |= (1 << pipe); /* Enable Ready Interrupt */
|
|
USB_MX.NRDYENB |= (1 << pipe); /* Enable Not Ready Interrupt */
|
|
break;
|
|
case USB_WRITEEND : /* End of data write */
|
|
case USB_WRITESHRT : /* End of data write */
|
|
USB_MX.BEMPENB |= (1 << pipe); /* Enable Empty Interrupt */
|
|
USB_MX.NRDYENB |= (1 << pipe); /* Enable Not Ready Interrupt */
|
|
break;
|
|
case USB_FIFOERROR : /* FIFO access error */
|
|
default:
|
|
forced_termination(pipe, (uint16_t)USB_DATA_ERR);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint16_t *USBPhyHw::get_pipectr_reg(uint16_t pipe)
|
|
{
|
|
if (pipe == USB_PIPE0) {
|
|
return (uint16_t *) & (USB_MX.DCPCTR);
|
|
} else {
|
|
return (uint16_t *) & (USB_MX.PIPE1CTR) + (pipe - USB_PIPE1);
|
|
}
|
|
}
|
|
|
|
uint16_t *USBPhyHw::get_pipetre_reg(uint16_t pipe)
|
|
{
|
|
if ((pipe >= USB_PIPE1) && (pipe <= USB_PIPE5)) {
|
|
return (uint16_t *) & (USB_MX.PIPE1TRE) + ((pipe - USB_PIPE1) * 2);
|
|
} else if ((pipe >= USB_PIPE9) && (pipe <= USB_PIPE10)) {
|
|
return (uint16_t *) & (USB_MX.PIPE9TRE) + ((pipe - USB_PIPE9) * 2);
|
|
} else if ((pipe >= USB_PIPE11) && (pipe <= USB_PIPE15)) {
|
|
return (uint16_t *) & (USB_MX.PIPEBTRE) + ((pipe - USB_PIPE11) * 2);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
uint16_t *USBPhyHw::get_pipetrn_reg(uint16_t pipe)
|
|
{
|
|
if ((pipe >= USB_PIPE1) && (pipe <= USB_PIPE5)) {
|
|
return (uint16_t *) & (USB_MX.PIPE1TRN) + ((pipe - USB_PIPE1) * 2);
|
|
} else if ((pipe >= USB_PIPE9) && (pipe <= USB_PIPE10)) {
|
|
return (uint16_t *) & (USB_MX.PIPE9TRN) + ((pipe - USB_PIPE9) * 2);
|
|
} else if ((pipe >= USB_PIPE11) && (pipe <= USB_PIPE15)) {
|
|
return (uint16_t *) & (USB_MX.PIPEBTRN) + ((pipe - USB_PIPE11) * 2);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
uint16_t *USBPhyHw::get_fifoctr_reg(uint16_t pipe)
|
|
{
|
|
uint16_t fifo_use = PIPE2FIFO(pipe);
|
|
|
|
if ((fifo_use & USB_FUNCTION_D0FIFO_USE) == USB_FUNCTION_D0FIFO_USE) {
|
|
return (uint16_t *) & (USB_MX.D0FIFOCTR);
|
|
} else if ((fifo_use & USB_FUNCTION_D1FIFO_USE) == USB_FUNCTION_D1FIFO_USE) {
|
|
return (uint16_t *) & (USB_MX.D1FIFOCTR);
|
|
} else {
|
|
return (uint16_t *) & (USB_MX.CFIFOCTR);
|
|
}
|
|
}
|
|
|
|
uint16_t *USBPhyHw::get_fifosel_reg(uint16_t pipe)
|
|
{
|
|
uint16_t fifo_use = PIPE2FIFO(pipe);
|
|
|
|
if ((fifo_use & USB_FUNCTION_D0FIFO_USE) == USB_FUNCTION_D0FIFO_USE) {
|
|
return (uint16_t *) & (USB_MX.D0FIFOSEL);
|
|
} else if ((fifo_use & USB_FUNCTION_D1FIFO_USE) == USB_FUNCTION_D1FIFO_USE) {
|
|
return (uint16_t *) & (USB_MX.D1FIFOSEL);
|
|
} else {
|
|
return (uint16_t *) & (USB_MX.CFIFOSEL);
|
|
}
|
|
}
|
|
|
|
uint32_t *USBPhyHw::get_fifo_reg(uint16_t pipe)
|
|
{
|
|
uint16_t fifo_use = PIPE2FIFO(pipe);
|
|
|
|
if ((fifo_use & USB_FUNCTION_D0FIFO_USE) == USB_FUNCTION_D0FIFO_USE) {
|
|
return (uint32_t *) & (USB_MX.D0FIFO);
|
|
} else if ((fifo_use & USB_FUNCTION_D1FIFO_USE) == USB_FUNCTION_D1FIFO_USE) {
|
|
return (uint32_t *) & (USB_MX.D1FIFO);
|
|
} else {
|
|
return (uint32_t *) & (USB_MX.CFIFO);
|
|
}
|
|
}
|
|
|
|
uint16_t USBPhyHw::get_pid(uint16_t pipe)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
|
|
p_reg = get_pipectr_reg(pipe);
|
|
return (uint16_t)(*p_reg & USB_PID);
|
|
}
|
|
|
|
void USBPhyHw::set_mbw(uint16_t pipe, uint16_t data)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
|
|
p_reg = get_fifosel_reg(pipe);
|
|
*p_reg &= (~USB_MBW);
|
|
if (data != 0) {
|
|
*p_reg |= data;
|
|
}
|
|
}
|
|
|
|
void USBPhyHw::set_pid(uint16_t pipe, uint16_t new_pid)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
uint16_t old_pid;
|
|
|
|
p_reg = get_pipectr_reg(pipe);
|
|
old_pid = get_pid(pipe);
|
|
|
|
switch (new_pid) {
|
|
case USB_PID_STALL:
|
|
if ((old_pid & USB_PID_BUF) == USB_PID_BUF) {
|
|
*p_reg &= (~USB_PID);
|
|
*p_reg |= USB_PID_STALL2;
|
|
} else {
|
|
*p_reg &= (~USB_PID);
|
|
*p_reg |= new_pid;
|
|
}
|
|
break;
|
|
case USB_PID_BUF:
|
|
if (((old_pid & USB_PID_STALL) == USB_PID_STALL) ||
|
|
((old_pid & USB_PID_STALL2) == USB_PID_STALL2)) {
|
|
*p_reg &= (~USB_PID);
|
|
*p_reg |= USB_PID_NAK;
|
|
}
|
|
*p_reg &= (~USB_PID);
|
|
*p_reg |= new_pid;
|
|
break;
|
|
case USB_PID_NAK:
|
|
if ((old_pid & USB_PID_STALL2) == USB_PID_STALL2) {
|
|
*p_reg &= (~USB_PID);
|
|
*p_reg |= USB_PID_STALL;
|
|
}
|
|
*p_reg &= (~USB_PID);
|
|
*p_reg |= new_pid;
|
|
|
|
do {
|
|
cpu_delay_1us(1);
|
|
p_reg = get_pipectr_reg(pipe);
|
|
} while ((*p_reg & USB_PBUSY) == USB_PBUSY);
|
|
break;
|
|
default:
|
|
*p_reg &= (~USB_PID);
|
|
*p_reg |= new_pid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void USBPhyHw::cpu_delay_1us(uint16_t time)
|
|
{
|
|
volatile uint32_t i = 38 * time;
|
|
|
|
while (i > 0) {
|
|
i--;
|
|
}
|
|
}
|
|
|
|
uint16_t USBPhyHw::EP2PIPE(uint16_t endpoint)
|
|
{
|
|
const struct PIPECFGREC *cfg;
|
|
|
|
for (cfg = &def_pipecfg[0]; cfg->pipesel != 0; cfg++) {
|
|
if (cfg->endpoint == endpoint) {
|
|
break;
|
|
}
|
|
}
|
|
return (cfg->pipesel & USB_CURPIPE);
|
|
}
|
|
|
|
uint16_t USBPhyHw::PIPE2EP(uint16_t pipe)
|
|
{
|
|
const struct PIPECFGREC *cfg;
|
|
|
|
if (pipe == USB_PIPE0) {
|
|
return 0;
|
|
}
|
|
for (cfg = &def_pipecfg[0]; cfg->pipesel != 0; cfg++) {
|
|
if ((cfg->pipesel & USB_CURPIPE) == pipe) {
|
|
break;
|
|
}
|
|
}
|
|
return cfg->endpoint;
|
|
}
|
|
|
|
uint16_t USBPhyHw::PIPE2FIFO(uint16_t pipe)
|
|
{
|
|
const struct PIPECFGREC *cfg;
|
|
uint16_t fifo_use;
|
|
|
|
if (pipe == USB_PIPE0) {
|
|
fifo_use = USB_FUNCTION_CFIFO_USE;
|
|
} else {
|
|
for (cfg = &def_pipecfg[0]; cfg->pipesel != 0; cfg++) {
|
|
if ((cfg->pipesel & USB_CURPIPE) == pipe) {
|
|
break;
|
|
}
|
|
}
|
|
if ((cfg->pipesel & USB_FUNCTION_D0FIFO_USE) == USB_FUNCTION_D0FIFO_USE) {
|
|
fifo_use = USB_FUNCTION_D0FIFO_USE;
|
|
} else if ((cfg->pipesel & USB_FUNCTION_D1FIFO_USE) == USB_FUNCTION_D1FIFO_USE) {
|
|
fifo_use = USB_FUNCTION_D1FIFO_USE;
|
|
} else {
|
|
fifo_use = USB_FUNCTION_CFIFO_USE;
|
|
}
|
|
}
|
|
|
|
return fifo_use;
|
|
}
|
|
|
|
void USBPhyHw::reset_usb(uint16_t clockmode)
|
|
{
|
|
#if (USB_FUNCTION_CH == 0)
|
|
if ((USB200.SYSCFG0 & USB_UPLLE) == USB_UPLLE) {
|
|
if ((USB200.SYSCFG0 & USB_UCKSEL) != clockmode) {
|
|
USB200.SUSPMODE &= ~(USB_SUSPMODE_SUSPM);
|
|
USB200.SYSCFG0 = 0;
|
|
USB200.SYSCFG0 = (clockmode | USB_UPLLE);
|
|
cpu_delay_1us(1000);
|
|
USB200.SUSPMODE |= USB_SUSPMODE_SUSPM;
|
|
} else {
|
|
USB200.SUSPMODE &= ~(USB_SUSPMODE_SUSPM);
|
|
cpu_delay_1us(1000);
|
|
USB200.SUSPMODE |= USB_SUSPMODE_SUSPM;
|
|
}
|
|
} else {
|
|
USB200.SUSPMODE &= ~(USB_SUSPMODE_SUSPM);
|
|
USB200.SYSCFG0 = 0;
|
|
USB200.SYSCFG0 = (clockmode | USB_UPLLE);
|
|
cpu_delay_1us(1000);
|
|
USB200.SUSPMODE |= USB_SUSPMODE_SUSPM;
|
|
}
|
|
#else
|
|
/* UCKSEL and UPLLE bit is only USB0. If USB1, set to SYSCFG0 for USB0. */
|
|
if ((USB200.SYSCFG0 & USB_UPLLE) == USB_UPLLE) {
|
|
if ((USB200.SYSCFG0 & USB_UCKSEL) != clockmode) {
|
|
USB201.SUSPMODE &= ~(USB_SUSPMODE_SUSPM);
|
|
USB200.SUSPMODE &= ~(USB_SUSPMODE_SUSPM);
|
|
USB201.SYSCFG0 = 0;
|
|
USB200.SYSCFG0 = 0;
|
|
USB200.SYSCFG0 = (clockmode | USB_UPLLE);
|
|
cpu_delay_1us(1000);
|
|
USB200.SUSPMODE |= USB_SUSPMODE_SUSPM;
|
|
USB201.SUSPMODE |= USB_SUSPMODE_SUSPM;
|
|
} else {
|
|
USB201.SUSPMODE &= ~(USB_SUSPMODE_SUSPM);
|
|
cpu_delay_1us(1000);
|
|
USB201.SUSPMODE |= USB_SUSPMODE_SUSPM;
|
|
}
|
|
} else {
|
|
USB201.SUSPMODE &= ~(USB_SUSPMODE_SUSPM);
|
|
USB200.SUSPMODE &= ~(USB_SUSPMODE_SUSPM);
|
|
USB201.SYSCFG0 = 0;
|
|
USB200.SYSCFG0 = 0;
|
|
USB200.SYSCFG0 = (clockmode | USB_UPLLE);
|
|
cpu_delay_1us(1000);
|
|
USB200.SUSPMODE |= USB_SUSPMODE_SUSPM;
|
|
USB201.SUSPMODE |= USB_SUSPMODE_SUSPM;
|
|
}
|
|
#endif
|
|
USB_MX.BUSWAIT = (uint16_t)(USB_BWAIT_3 & USB_BWAIT); /* 3 : 5 access cycles waits */
|
|
USB_MX.CFIFOSEL = USB_MBW_32;
|
|
USB_MX.D0FIFOSEL = USB_MBW_32;
|
|
USB_MX.D1FIFOSEL = USB_MBW_32;
|
|
}
|
|
|
|
bool USBPhyHw::chk_vbsts(void)
|
|
{
|
|
uint16_t buf1;
|
|
uint16_t buf2;
|
|
uint16_t buf3;
|
|
bool connect_flg = false;
|
|
|
|
/* VBUS chattering cut */
|
|
do {
|
|
buf1 = USB_MX.INTSTS0;
|
|
cpu_delay_1us(10);
|
|
buf2 = USB_MX.INTSTS0;
|
|
cpu_delay_1us(10);
|
|
buf3 = USB_MX.INTSTS0;
|
|
} while (((buf1 & USB_VBSTS) != (buf2 & USB_VBSTS)) || ((buf2 & USB_VBSTS) != (buf3 & USB_VBSTS)));
|
|
|
|
/* VBUS status judge */
|
|
if ((buf1 & USB_VBSTS) != (uint16_t)0) {
|
|
connect_flg = true;
|
|
}
|
|
|
|
return connect_flg;
|
|
}
|
|
|
|
void USBPhyHw::ctrl_end(uint16_t status)
|
|
{
|
|
/* Interrupt disable */
|
|
USB_MX.BEMPENB &= (~(1 << USB_PIPE0)); /* Disable Empty Interrupt */
|
|
USB_MX.BRDYENB &= (~(1 << USB_PIPE0)); /* Disable Ready Interrupt */
|
|
USB_MX.NRDYENB &= (~(1 << USB_PIPE0)); /* Disable Not Ready Interrupt */
|
|
|
|
set_mbw(USB_PIPE0, USB_MBW_32);
|
|
|
|
if ((status == USB_DATA_ERR) || (status == USB_DATA_OVR)) {
|
|
set_pid(USB_PIPE0, USB_PID_STALL); /* Request error */
|
|
} else if (status == USB_DATA_STOP) {
|
|
set_pid(USB_PIPE0, USB_PID_NAK); /* Pipe stop */
|
|
} else {
|
|
USB_MX.DCPCTR |= USB_CCPL; /* Set CCPL bit */
|
|
}
|
|
}
|
|
|
|
void USBPhyHw::data_end(uint16_t pipe, uint16_t status)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
|
|
/* Disable Interrupt */
|
|
USB_MX.BRDYENB &= (~(1 << pipe)); /* Disable Ready Interrupt */
|
|
USB_MX.NRDYENB &= (~(1 << pipe)); /* Disable Not Ready Interrupt */
|
|
USB_MX.BEMPENB &= (~(1 << pipe)); /* Disable Empty Interrupt */
|
|
|
|
set_pid(pipe, USB_PID_NAK); /* Set NAK */
|
|
|
|
/* Disable Transaction count */
|
|
p_reg = get_pipetre_reg(pipe);
|
|
if (p_reg != NULL) {
|
|
*p_reg &= (~USB_TRENB);
|
|
*p_reg |= USB_TRCLR;
|
|
}
|
|
|
|
if (pipe_ctrl[pipe].enable) {
|
|
/* Check PIPE TYPE */
|
|
USB_MX.PIPESEL = pipe; /* Pipe select */
|
|
if ((USB_MX.PIPECFG & USB_TYPFIELD) != USB_TYPFIELD_ISO) {
|
|
/* Transfer information set */
|
|
pipe_ctrl[pipe].enable = false;
|
|
pipe_ctrl[pipe].status = status;
|
|
} else if ((uint16_t)(USB_MX.PIPECFG & USB_DIRFIELD) == USB_BUF2FIFO) {
|
|
/* ISO OUT Transfer (restart) */
|
|
pipe_ctrl[pipe].status = USB_DATA_WRITING;
|
|
} else {
|
|
/* ISO IN Transfer (restart) */
|
|
pipe_ctrl[pipe].status = USB_DATA_READING;
|
|
}
|
|
}
|
|
}
|
|
|
|
void USBPhyHw::forced_termination(uint16_t pipe, uint16_t status)
|
|
{
|
|
volatile uint16_t *p_reg;
|
|
|
|
/* Disable Interrupt */
|
|
USB_MX.BRDYENB &= (~(1 << pipe)); /* Disable Ready Interrupt */
|
|
USB_MX.NRDYENB &= (~(1 << pipe)); /* Disable Not Ready Interrupt */
|
|
USB_MX.BEMPENB &= (~(1 << pipe)); /* Disable Empty Interrupt */
|
|
|
|
set_pid(pipe, USB_PID_NAK); /* Set NAK */
|
|
|
|
/* Disable Transaction count */
|
|
p_reg = get_pipetre_reg(pipe);
|
|
if (p_reg != NULL) {
|
|
*p_reg &= (~USB_TRENB);
|
|
*p_reg |= USB_TRCLR;
|
|
}
|
|
|
|
set_mbw(pipe, USB_MBW_32);
|
|
|
|
chg_curpipe(pipe, 0); /* Changes the FIFO port by the pipe. */
|
|
|
|
p_reg = get_pipectr_reg(pipe);
|
|
/* Buffer Clear */
|
|
*p_reg |= USB_ACLRM;
|
|
*p_reg &= ~USB_ACLRM;
|
|
|
|
pipe_ctrl[pipe].enable = false;
|
|
pipe_ctrl[pipe].status = status;
|
|
}
|
|
|
|
#endif
|