openwrt/target/linux/lantiq/files/drivers/usb/ifxhcd/ifxhcd_es.c

550 lines
15 KiB
C

/*****************************************************************************
** FILE NAME : ifxhcd_es.c
** PROJECT : IFX USB sub-system V3
** MODULES : IFX USB sub-system Host and Device driver
** SRC VERSION : 1.0
** DATE : 1/Jan/2009
** AUTHOR : Chen, Howard
** DESCRIPTION : The file contain function to enable host mode USB-IF Electrical Test function.
*****************************************************************************/
/*!
\file ifxhcd_es.c
\ingroup IFXUSB_DRIVER_V3
\brief The file contain function to enable host mode USB-IF Electrical Test function.
*/
#include <linux/version.h>
#include "ifxusb_version.h"
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/dma-mapping.h>
#include "ifxusb_plat.h"
#include "ifxusb_regs.h"
#include "ifxusb_cif.h"
#include "ifxhcd.h"
#ifdef __WITH_HS_ELECT_TST__
/*
* Quick and dirty hack to implement the HS Electrical Test
* SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
*
* This code was copied from our userspace app "hset". It sends a
* Get Device Descriptor control sequence in two parts, first the
* Setup packet by itself, followed some time later by the In and
* Ack packets. Rather than trying to figure out how to add this
* functionality to the normal driver code, we just hijack the
* hardware, using these two function to drive the hardware
* directly.
*/
void do_setup(ifxusb_core_if_t *_core_if)
{
ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs;
ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs;
ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0];
uint32_t *data_fifo = _core_if->data_fifo[0];
gint_data_t gintsts;
hctsiz_data_t hctsiz;
hcchar_data_t hcchar;
haint_data_t haint;
hcint_data_t hcint;
/* Enable HAINTs */
ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001);
/* Enable HCINTs */
ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
/* Read HAINT */
haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
//fprintf(stderr, "HAINT: %08x\n", haint.d32);
/* Read HCINT */
hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
//fprintf(stderr, "HCINT: %08x\n", hcint.d32);
/* Read HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
/* Clear HCINT */
ifxusb_wreg(&hc_regs->hcint, hcint.d32);
/* Clear HAINT */
ifxusb_wreg(&hc_global_regs->haint, haint.d32);
/* Clear GINTSTS */
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
/*
* Send Setup packet (Get Device Descriptor)
*/
/* Make sure channel is disabled */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
if (hcchar.b.chen) {
//fprintf(stderr, "Channel already enabled 1, HCCHAR = %08x\n", hcchar.d32);
hcchar.b.chdis = 1;
// hcchar.b.chen = 1;
ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
//sleep(1);
mdelay(1000);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
/* Read HAINT */
haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
//fprintf(stderr, "HAINT: %08x\n", haint.d32);
/* Read HCINT */
hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
//fprintf(stderr, "HCINT: %08x\n", hcint.d32);
/* Read HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
/* Clear HCINT */
ifxusb_wreg(&hc_regs->hcint, hcint.d32);
/* Clear HAINT */
ifxusb_wreg(&hc_global_regs->haint, haint.d32);
/* Clear GINTSTS */
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//if (hcchar.b.chen) {
// fprintf(stderr, "** Channel _still_ enabled 1, HCCHAR = %08x **\n", hcchar.d32);
//}
}
/* Set HCTSIZ */
hctsiz.d32 = 0;
hctsiz.b.xfersize = 8;
hctsiz.b.pktcnt = 1;
hctsiz.b.pid = IFXUSB_HC_PID_SETUP;
ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32);
/* Set HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL;
hcchar.b.epdir = 0;
hcchar.b.epnum = 0;
hcchar.b.mps = 8;
hcchar.b.chen = 1;
ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
/* Fill FIFO with Setup data for Get Device Descriptor */
ifxusb_wreg(data_fifo++, 0x01000680);
ifxusb_wreg(data_fifo++, 0x00080000);
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32);
/* Wait for host channel interrupt */
do {
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
} while (gintsts.b.hcintr == 0);
//fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32);
/* Disable HCINTs */
ifxusb_wreg(&hc_regs->hcintmsk, 0x0000);
/* Disable HAINTs */
ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000);
/* Read HAINT */
haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
//fprintf(stderr, "HAINT: %08x\n", haint.d32);
/* Read HCINT */
hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
//fprintf(stderr, "HCINT: %08x\n", hcint.d32);
/* Read HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
/* Clear HCINT */
ifxusb_wreg(&hc_regs->hcint, hcint.d32);
/* Clear HAINT */
ifxusb_wreg(&hc_global_regs->haint, haint.d32);
/* Clear GINTSTS */
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
}
void do_in_ack(ifxusb_core_if_t *_core_if)
{
ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs;
ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs;
ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0];
uint32_t *data_fifo = _core_if->data_fifo[0];
gint_data_t gintsts;
hctsiz_data_t hctsiz;
hcchar_data_t hcchar;
haint_data_t haint;
hcint_data_t hcint;
grxsts_data_t grxsts;
/* Enable HAINTs */
ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001);
/* Enable HCINTs */
ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
/* Read HAINT */
haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
//fprintf(stderr, "HAINT: %08x\n", haint.d32);
/* Read HCINT */
hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
//fprintf(stderr, "HCINT: %08x\n", hcint.d32);
/* Read HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
/* Clear HCINT */
ifxusb_wreg(&hc_regs->hcint, hcint.d32);
/* Clear HAINT */
ifxusb_wreg(&hc_global_regs->haint, haint.d32);
/* Clear GINTSTS */
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
/*
* Receive Control In packet
*/
/* Make sure channel is disabled */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
if (hcchar.b.chen) {
//fprintf(stderr, "Channel already enabled 2, HCCHAR = %08x\n", hcchar.d32);
hcchar.b.chdis = 1;
hcchar.b.chen = 1;
ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
//sleep(1);
mdelay(1000);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
/* Read HAINT */
haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
//fprintf(stderr, "HAINT: %08x\n", haint.d32);
/* Read HCINT */
hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
//fprintf(stderr, "HCINT: %08x\n", hcint.d32);
/* Read HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
/* Clear HCINT */
ifxusb_wreg(&hc_regs->hcint, hcint.d32);
/* Clear HAINT */
ifxusb_wreg(&hc_global_regs->haint, haint.d32);
/* Clear GINTSTS */
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//if (hcchar.b.chen) {
// fprintf(stderr, "** Channel _still_ enabled 2, HCCHAR = %08x **\n", hcchar.d32);
//}
}
/* Set HCTSIZ */
hctsiz.d32 = 0;
hctsiz.b.xfersize = 8;
hctsiz.b.pktcnt = 1;
hctsiz.b.pid = IFXUSB_HC_PID_DATA1;
ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32);
/* Set HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL;
hcchar.b.epdir = 1;
hcchar.b.epnum = 0;
hcchar.b.mps = 8;
hcchar.b.chen = 1;
ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32);
/* Wait for receive status queue interrupt */
do {
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
} while (gintsts.b.rxstsqlvl == 0);
//fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32);
/* Read RXSTS */
grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp);
//fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32);
/* Clear RXSTSQLVL in GINTSTS */
gintsts.d32 = 0;
gintsts.b.rxstsqlvl = 1;
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
switch (grxsts.hb.pktsts) {
case IFXUSB_HSTS_DATA_UPDT:
/* Read the data into the host buffer */
if (grxsts.hb.bcnt > 0) {
int i;
int word_count = (grxsts.hb.bcnt + 3) / 4;
for (i = 0; i < word_count; i++) {
(void)ifxusb_rreg(data_fifo++);
}
}
//fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.hb.bcnt);
break;
default:
//fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n");
break;
}
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32);
/* Wait for receive status queue interrupt */
do {
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
} while (gintsts.b.rxstsqlvl == 0);
//fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32);
/* Read RXSTS */
grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp);
//fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32);
/* Clear RXSTSQLVL in GINTSTS */
gintsts.d32 = 0;
gintsts.b.rxstsqlvl = 1;
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
switch (grxsts.hb.pktsts) {
case IFXUSB_HSTS_XFER_COMP:
break;
default:
//fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n");
break;
}
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32);
/* Wait for host channel interrupt */
do {
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
} while (gintsts.b.hcintr == 0);
//fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32);
/* Read HAINT */
haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
//fprintf(stderr, "HAINT: %08x\n", haint.d32);
/* Read HCINT */
hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
//fprintf(stderr, "HCINT: %08x\n", hcint.d32);
/* Read HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
/* Clear HCINT */
ifxusb_wreg(&hc_regs->hcint, hcint.d32);
/* Clear HAINT */
ifxusb_wreg(&hc_global_regs->haint, haint.d32);
/* Clear GINTSTS */
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
// usleep(100000);
// mdelay(100);
mdelay(1);
/*
* Send handshake packet
*/
/* Read HAINT */
haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
//fprintf(stderr, "HAINT: %08x\n", haint.d32);
/* Read HCINT */
hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
//fprintf(stderr, "HCINT: %08x\n", hcint.d32);
/* Read HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
/* Clear HCINT */
ifxusb_wreg(&hc_regs->hcint, hcint.d32);
/* Clear HAINT */
ifxusb_wreg(&hc_global_regs->haint, haint.d32);
/* Clear GINTSTS */
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
/* Make sure channel is disabled */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
if (hcchar.b.chen) {
//fprintf(stderr, "Channel already enabled 3, HCCHAR = %08x\n", hcchar.d32);
hcchar.b.chdis = 1;
hcchar.b.chen = 1;
ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
//sleep(1);
mdelay(1000);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
/* Read HAINT */
haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
//fprintf(stderr, "HAINT: %08x\n", haint.d32);
/* Read HCINT */
hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
//fprintf(stderr, "HCINT: %08x\n", hcint.d32);
/* Read HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
/* Clear HCINT */
ifxusb_wreg(&hc_regs->hcint, hcint.d32);
/* Clear HAINT */
ifxusb_wreg(&hc_global_regs->haint, haint.d32);
/* Clear GINTSTS */
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//if (hcchar.b.chen) {
// fprintf(stderr, "** Channel _still_ enabled 3, HCCHAR = %08x **\n", hcchar.d32);
//}
}
/* Set HCTSIZ */
hctsiz.d32 = 0;
hctsiz.b.xfersize = 0;
hctsiz.b.pktcnt = 1;
hctsiz.b.pid = IFXUSB_HC_PID_DATA1;
ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32);
/* Set HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL;
hcchar.b.epdir = 0;
hcchar.b.epnum = 0;
hcchar.b.mps = 8;
hcchar.b.chen = 1;
ifxusb_wreg(&hc_regs->hcchar, hcchar.d32);
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32);
/* Wait for host channel interrupt */
do {
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
} while (gintsts.b.hcintr == 0);
//fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32);
/* Disable HCINTs */
ifxusb_wreg(&hc_regs->hcintmsk, 0x0000);
/* Disable HAINTs */
ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000);
/* Read HAINT */
haint.d32 = ifxusb_rreg(&hc_global_regs->haint);
//fprintf(stderr, "HAINT: %08x\n", haint.d32);
/* Read HCINT */
hcint.d32 = ifxusb_rreg(&hc_regs->hcint);
//fprintf(stderr, "HCINT: %08x\n", hcint.d32);
/* Read HCCHAR */
hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar);
//fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
/* Clear HCINT */
ifxusb_wreg(&hc_regs->hcint, hcint.d32);
/* Clear HAINT */
ifxusb_wreg(&hc_global_regs->haint, haint.d32);
/* Clear GINTSTS */
ifxusb_wreg(&global_regs->gintsts, gintsts.d32);
/* Read GINTSTS */
gintsts.d32 = ifxusb_rreg(&global_regs->gintsts);
//fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
}
#endif //__WITH_HS_ELECT_TST__