/***************************************************************************** ** FILE NAME : dwc_otg_proc.c ** PROJECT : USB Host and Device driver ** MODULES : USB Host and Device driver ** SRC VERSION : 2.0 ** DATE : 1/March/2008 ** AUTHOR : Chen, Howard based on Synopsys Original ** DESCRIPTION : The diagnostic interface will provide access to the controller ** for bringing up the hardware and testing. The Linux driver ** attributes feature will be used to provide the Linux Diagnostic ** Interface. These attributes are accessed through sysfs. ** FUNCTIONS : ** COMPILER : gcc ** REFERENCE : ** COPYRIGHT : ** Version Control Section ** ** $Author$ ** $Date$ ** $Revisions$ ** $Log$ Revision history *****************************************************************************/ #include #include "ifxusb_version.h" /*! \file dwc_otg_proc.c \brief This file contains the interface to the Linux device attributes. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && defined(USE_PROC_FS) #include #include #include "dwc_otg_driver.h" #include "dwc_otg_cil.h" #include "dwc_otg_ifx.h" extern int ifx_proc_addproc(char *funcname, read_proc_t *hookfuncr, write_proc_t *hookfuncw); extern void ifx_proc_delproc(char * funcname); extern dwc_otg_device_t *dwc_get_drvdata(void); /** * Show the register offset of the Register Access. */ static ssize_t regoffset_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0; dwc_otg_device_t *otg_dev = dwc_get_drvdata(); len += snprintf(buf+len, sizeof("0xFFFFFFFF\n")+1,"0x%08x\n", otg_dev->reg_offset); *eof = 1; return len; } /** * Set the register offset for the next Register Access Read/Write */ static ssize_t regoffset_store(struct file *file, const char *buffer, unsigned long count, void *data) { char buf[10]; int i = 0; dwc_otg_device_t *otg_dev = dwc_get_drvdata(); uint32_t offset; if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) return -EFAULT; offset = simple_strtoul(buf, NULL, 16); //dev_dbg(_dev, "Offset=0x%08x\n", offset); if (offset < REGSIZE ){ otg_dev->reg_offset = offset; }else{ dev_err( _dev, "invalid offset\n" ); } return count; } /** * Show the value of the register at the offset in the reg_offset * attribute. */ static ssize_t regvalue_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) { dwc_otg_device_t *otg_dev = dwc_get_drvdata(); uint32_t val; volatile uint32_t *addr; int len = 0; if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base){ /* Calculate the address */ addr = (uint32_t*)(otg_dev->reg_offset + (uint8_t*)otg_dev->base); //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr); val = dwc_read_reg32( addr ); len += snprintf(buf+len, sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n")+1, "Reg@0x%06x = 0x%08x\n", otg_dev->reg_offset, val); *eof = 1; return len; }else{ dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->reg_offset); len += sprintf(buf+len, "invalid offset\n" ); *eof = 1; return len; } } /** * Store the value in the register at the offset in the reg_offset * attribute. */ static ssize_t regvalue_store(struct file *file, const char *buffer, unsigned long count, void *data) { char buf[10]; int i = 0; dwc_otg_device_t *otg_dev = dwc_get_drvdata(); volatile uint32_t * addr; uint32_t val; if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) return -EFAULT; val = simple_strtoul(buf, NULL, 16); //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val); if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base){ /* Calculate the address */ addr = (uint32_t*)(otg_dev->reg_offset + (uint8_t*)otg_dev->base); //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr); dwc_write_reg32( addr, val ); }else{ dev_err(_dev, "Invalid Register Offset (0x%08x)\n", otg_dev->reg_offset); } return count; } /** * Dump global registers */ static ssize_t gregdump_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int i; volatile uint32_t *addr; dwc_otg_device_t *otg_dev = dwc_get_drvdata(); dwc_otg_core_if_t *_core_if = otg_dev->core_if; int len = 0; // global registers start. len += sprintf(buf+len, "Core Global Registers\n"); addr=&_core_if->core_global_regs->gotgctl; len += sprintf(buf+len, "GOTGCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gotgint; len += sprintf(buf+len, "GOTGINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gahbcfg; len += sprintf(buf+len, "GAHBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gusbcfg; len += sprintf(buf+len, "GUSBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->grstctl; len += sprintf(buf+len, "GRSTCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gintsts; len += sprintf(buf+len, "GINTSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gintmsk; len += sprintf(buf+len, "GINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->grxstsr; len += sprintf(buf+len, "GRXSTSR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); //addr=&_core_if->core_global_regs->grxstsp; //len += sprintf(buf+len, "GRXSTSP @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->grxfsiz; len += sprintf(buf+len, "GRXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gnptxfsiz; len += sprintf(buf+len, "GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gnptxsts; len += sprintf(buf+len, "GNPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gi2cctl; len += sprintf(buf+len, "GI2CCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gpvndctl; len += sprintf(buf+len, "GPVNDCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->ggpio; len += sprintf(buf+len, "GGPIO @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->guid; len += sprintf(buf+len, "GUID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->gsnpsid; len += sprintf(buf+len, "GSNPSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->ghwcfg1; len += sprintf(buf+len, "GHWCFG1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->ghwcfg2; len += sprintf(buf+len, "GHWCFG2 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->ghwcfg3; len += sprintf(buf+len, "GHWCFG3 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->ghwcfg4; len += sprintf(buf+len, "GHWCFG4 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->core_global_regs->hptxfsiz; len += sprintf(buf+len, "HPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); for (i=0; i<_core_if->hwcfg4.b.num_dev_perio_in_ep; i++) { addr=&_core_if->core_global_regs->dptxfsiz[i]; len += sprintf(buf+len, "DPTXFSIZ[%d] @0x%08X : 0x%08X\n",i,(uint32_t)addr,dwc_read_reg32(addr)); } // global registers end. *eof = 1; return len; } /** * Dump HOST registers */ static ssize_t hregdump_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) { #ifdef DWC_IS_HOST int i; volatile uint32_t *addr; dwc_otg_device_t *otg_dev = dwc_get_drvdata(); dwc_otg_core_if_t *_core_if = otg_dev->core_if; int len = 0; // host registers start. len += sprintf(buf+len, "Host Global Registers\n"); addr=&_core_if->host_if->host_global_regs->hcfg; len += sprintf(buf+len, "HCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->host_global_regs->hfir; len += sprintf(buf+len, "HFIR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->host_global_regs->hfnum; len += sprintf(buf+len, "HFNUM @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->host_global_regs->hptxsts; len += sprintf(buf+len, "HPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->host_global_regs->haint; len += sprintf(buf+len, "HAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->host_global_regs->haintmsk; len += sprintf(buf+len, "HAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=_core_if->host_if->hprt0; len += sprintf(buf+len, "HPRT0 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); for (i=0; i<_core_if->core_params->host_channels; i++){ len += sprintf(buf+len, "Host Channel %d Specific Registers\n", i); addr=&_core_if->host_if->hc_regs[i]->hcchar; len += sprintf(buf+len, "HCCHAR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->hc_regs[i]->hcsplt; len += sprintf(buf+len, "HCSPLT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->hc_regs[i]->hcint; len += sprintf(buf+len, "HCINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->hc_regs[i]->hcintmsk; len += sprintf(buf+len, "HCINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->hc_regs[i]->hctsiz; len += sprintf(buf+len, "HCTSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->host_if->hc_regs[i]->hcdma; len += sprintf(buf+len, "HCDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); } // host registers end. *eof = 1; return len; #else // DWC_IS_HOST return 0; #endif } /** * Dump DEVICE registers */ static ssize_t dregdump_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) { #ifdef DWC_IS_DEVICE int i; volatile uint32_t *addr; dwc_otg_device_t *otg_dev = dwc_get_drvdata(); dwc_otg_core_if_t *_core_if = otg_dev->core_if; int len = 0; // device registers start. len += sprintf(buf+len, "Device Global Registers\n"); addr=&_core_if->dev_if->dev_global_regs->dcfg; len += sprintf(buf+len, "DCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->dev_global_regs->dctl; len += sprintf(buf+len, "DCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->dev_global_regs->dsts; len += sprintf(buf+len, "DSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->dev_global_regs->diepmsk; len += sprintf(buf+len, "DIEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->dev_global_regs->doepmsk; len += sprintf(buf+len, "DOEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->dev_global_regs->daint; len += sprintf(buf+len, "DAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->dev_global_regs->daintmsk; len += sprintf(buf+len, "DAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->dev_global_regs->dtknqr1; len += sprintf(buf+len, "DTKNQR1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); if (_core_if->hwcfg2.b.dev_token_q_depth > 6){ addr=&_core_if->dev_if->dev_global_regs->dtknqr2; len += sprintf(buf+len, "DTKNQR2 @0x%08X : 0x%08X\n", (uint32_t)addr,dwc_read_reg32(addr)); } addr=&_core_if->dev_if->dev_global_regs->dvbusdis; len += sprintf(buf+len, "DVBUSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->dev_global_regs->dvbuspulse; len += sprintf(buf+len, "DVBUSPULSE @0x%08X : 0x%08X\n", (uint32_t)addr,dwc_read_reg32(addr)); if (_core_if->hwcfg2.b.dev_token_q_depth > 14){ addr=&_core_if->dev_if->dev_global_regs->dtknqr3; len += sprintf(buf+len, "DTKNQR3 @0x%08X : 0x%08X\n", (uint32_t)addr, dwc_read_reg32(addr)); } if (_core_if->hwcfg2.b.dev_token_q_depth > 22){ addr=&_core_if->dev_if->dev_global_regs->dtknqr4; len += sprintf(buf+len, "DTKNQR4 @0x%08X : 0x%08X\n", (uint32_t)addr, dwc_read_reg32(addr)); } // Winder: I just dump ep0-3 because we just use ep0-3. // for (i=0; i< _core_if->dev_if->num_eps; i++) for (i=0; i<4; i++){ len += sprintf(buf+len, "Device IN EP %d Registers\n", i); addr=&_core_if->dev_if->in_ep_regs[i]->diepctl; len += sprintf(buf+len, "DIEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->in_ep_regs[i]->diepint; len += sprintf(buf+len, "DIEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->in_ep_regs[i]->dieptsiz; len += sprintf(buf+len, "DIETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->in_ep_regs[i]->diepdma; len += sprintf(buf+len, "DIEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); len += sprintf(buf+len, "Device OUT EP %d Registers\n", i); addr=&_core_if->dev_if->out_ep_regs[i]->doepctl; len += sprintf(buf+len, "DOEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->out_ep_regs[i]->doepfn; len += sprintf(buf+len, "DOEPFN @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->out_ep_regs[i]->doepint; len += sprintf(buf+len, "DOEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->out_ep_regs[i]->doeptsiz; len += sprintf(buf+len, "DOETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); addr=&_core_if->dev_if->out_ep_regs[i]->doepdma; len += sprintf(buf+len, "DOEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); } // device registers end. *eof = 1; return len; #else // DWC_IS_DEVICE return 0; #endif } /** * Dump current module parameters. */ extern dwc_otg_core_params_t *dwc_otg_get_module_params(void); extern uint32_t g_dbg_lvl; static ssize_t moddump_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0; dwc_otg_core_params_t *modules_param = dwc_otg_get_module_params(); dwc_otg_device_t *otg_dev = dwc_get_drvdata(); len += sprintf(buf+len, "g_dbg_lvl"": %d\n", g_dbg_lvl); len += sprintf(buf+len, "dwc_iomem_base"": 0x%08x\n", (unsigned int)otg_dev->base); len += sprintf(buf+len, "dwc_irq"": %d\n", otg_dev->irq); len += sprintf(buf+len, "OPT mode"": %d\n", modules_param->opt); len += sprintf(buf+len, "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256"": %d\n", modules_param->dma_burst_size); len += sprintf(buf+len, "Speed 0=High Speed 1=Full Speed"": %d\n", modules_param->speed); len += sprintf(buf+len, "Total number of words in the data FIFO memory 32-32768"": %d\n", modules_param->data_fifo_size); #ifdef DWC_IS_DEVICE len += sprintf(buf+len, "Number of words in the Device Rx FIFO 16-32768"": %d\n", modules_param->dev_rx_fifo_size); len += sprintf(buf+len, "Number of words in the Device non-periodic Tx FIFO 16-32768"": %d\n", modules_param->dev_nperio_tx_fifo_size); len += sprintf(buf+len, "Number of words in the Device periodic Tx FIFO 4-768"": %d\n", modules_param->dev_perio_tx_fifo_size[0]); len += sprintf(buf+len, "The number of endpoints in addition to EP0 available for device mode 1-15"": %d\n", modules_param->dev_endpoints); #endif #ifdef DWC_IS_HOST len += sprintf(buf+len, "Number of words in the host Rx FIFO 16-32768"": %d\n", modules_param->host_rx_fifo_size); len += sprintf(buf+len, "Number of words in the host non-periodic Tx FIFO 16-32768"": %d\n", modules_param->host_nperio_tx_fifo_size); len += sprintf(buf+len, "Number of words in the host periodic Tx FIFO 16-32768"": %d\n", modules_param->host_perio_tx_fifo_size); len += sprintf(buf+len, "The number of host channel registers to use 1-16"": %d\n", modules_param->host_channels); #endif len += sprintf(buf+len, "The maximum transfer size supported in bytes 2047-65535"": %d\n", modules_param->max_transfer_size); len += sprintf(buf+len, "The maximum number of packets in a transfer 15-511"": %d\n", modules_param->max_packet_count); len += sprintf(buf+len, "Specifies the UTMI+ Data Width 8 or 16 bits"": %d\n", modules_param->phy_utmi_width); //16 *eof = 1; return len; } /** * Create the proc files. */ void dwc_otg_proc_init(void) { // add proc filesystem. ifx_proc_addproc("regoffset", regoffset_show, regoffset_store); ifx_proc_addproc("regvalue", regvalue_show, regvalue_store); ifx_proc_addproc("gregdump", gregdump_show, NULL); ifx_proc_addproc("hregdump", hregdump_show, NULL); ifx_proc_addproc("dregdump", dregdump_show, NULL); ifx_proc_addproc("moddump", moddump_show, NULL); } void dwc_otg_proc_clean(void) { // remove proc filesystem. ifx_proc_delproc("regoffset"); ifx_proc_delproc("regvalue"); ifx_proc_delproc("gregdump"); ifx_proc_delproc("hregdump"); ifx_proc_delproc("dregdump"); ifx_proc_delproc("moddump"); } #endif //LINUX24 only