?? dwc_otg_cil.c
字號(hào):
/* ========================================================================== * * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless * otherwise expressly agreed to in writing between Synopsys and you. * * The Software IS NOT an item of Licensed Software or Licensed Product under * any End User Software License Agreement or Agreement for Licensed Product * with Synopsys or any supplement thereto. You are permitted to use and * redistribute this Software in source and binary forms, with or without * modification, provided that redistributions of source code must retain this * notice. You may not view, use, disclose, copy or distribute this file or * any information contained herein except pursuant to this license grant from * Synopsys. If you do not agree with this notice, including the disclaimer * below, then you are not authorized to use the Software. * * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * ========================================================================== *//** @file * * The Core Interface Layer provides basic services for accessing and * managing the DWC_otg hardware. These services are used by both the * Host Controller Driver and the Peripheral Controller Driver. * * The CIL manages the memory map for the core so that the HCD and PCD * don't have to do this separately. It also handles basic tasks like * reading/writing the registers and data FIFOs in the controller. * Some of the data access functions provide encapsulation of several * operations required to perform a task, such as writing multiple * registers to start a transfer. Finally, the CIL performs basic * services that are not specific to either the host or device modes * of operation. These services include management of the OTG Host * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A * Diagnostic API is also provided to allow testing of the controller * hardware. * * The Core Interface Layer has the following requirements: * - Provides basic controller operations. * - Minimal use of OS services. * - The OS services used will be abstracted by using inline functions * or macros. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/device.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/stat.h> /* permission constants */#include <linux/version.h>#include <linux/platform_device.h>#include <asm/unaligned.h>#include <asm/arch/regs-usb-otg-hs.h>#ifdef DEBUG#include <linux/jiffies.h>#endif#include "dwc_otg_plat.h"#include "dwc_otg_regs.h"#include "dwc_otg_cil.h"/** * This function is called to initialize the DWC_otg CSR data * structures. The register addresses in the device and host * structures are initialized from the base address supplied by the * caller. The calling function must make the OS calls to get the * base address of the DWC_otg controller registers. The core_params * argument holds the parameters that specify how the core should be * configured. * * @param[in] _reg_base_addr Base address of DWC_otg core registers * @param[in] _core_params Pointer to the core configuration parameters * */dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr, dwc_otg_core_params_t * _core_params){ dwc_otg_core_if_t *core_if = 0; dwc_otg_dev_if_t *dev_if = 0; dwc_otg_host_if_t *host_if = 0; uint8_t *reg_base = (uint8_t *) _reg_base_addr; int i = 0; dbg_otg("%s(%p,%p)\n", __func__, _reg_base_addr, _core_params); core_if = kmalloc(sizeof(dwc_otg_core_if_t), GFP_KERNEL); if (core_if == 0) { printk("Allocation of dwc_otg_core_if_t failed\n"); return 0; } memset(core_if, 0, sizeof(dwc_otg_core_if_t)); core_if->core_params = _core_params; core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base; /* * Allocate the Device Mode structures. */ dev_if = kmalloc(sizeof(dwc_otg_dev_if_t), GFP_KERNEL); if (dev_if == 0) { printk("Allocation of dwc_otg_dev_if_t failed\n"); kfree(core_if); return 0; } dev_if->dev_global_regs = (dwc_otg_device_global_regs_t *) (reg_base + DWC_DEV_GLOBAL_REG_OFFSET); for (i = 0; i < MAX_EPS_CHANNELS; i++) { dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *) (reg_base + DWC_DEV_IN_EP_REG_OFFSET + (i * DWC_EP_REG_OFFSET)); dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *) (reg_base + DWC_DEV_OUT_EP_REG_OFFSET + (i * DWC_EP_REG_OFFSET)); dbg_otg("in_ep_regs[%d]->diepctl=%p\n", i, &dev_if->in_ep_regs[i]->diepctl); dbg_otg("out_ep_regs[%d]->doepctl=%p\n", i, &dev_if->out_ep_regs[i]->doepctl); } /* we cannot find dest speed of USB interface */ dev_if->speed = 0; core_if->dev_if = dev_if; /* * Allocate the Host Mode structures. */ host_if = kmalloc(sizeof(dwc_otg_host_if_t), GFP_KERNEL); if (host_if == 0) { printk("Allocation of dwc_otg_host_if_t failed\n"); kfree(dev_if); kfree(core_if); return 0; } host_if->host_global_regs = (dwc_otg_host_global_regs_t *) (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET); host_if->hprt0 = (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET); for (i = 0; i < MAX_EPS_CHANNELS; i++) { host_if->hc_regs[i] = (dwc_otg_hc_regs_t *) (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET + (i * DWC_OTG_CHAN_REGS_OFFSET)); dbg_otg("hc_reg[%d]->hcchar=%p\n", i, &host_if->hc_regs[i]->hcchar); } host_if->num_host_channels = MAX_EPS_CHANNELS; core_if->host_if = host_if; for (i = 0; i < MAX_EPS_CHANNELS; i++) { core_if->data_fifo[i] = (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET + (i * DWC_OTG_DATA_FIFO_SIZE)); dbg_otg("data_fifo[%d]=0x%08x\n", i, (unsigned) core_if->data_fifo[i]); } core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET); /* * Store the contents of the hardware configuration registers here for * easy access later. */ core_if->hwcfg1.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg1); core_if->hwcfg2.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg2); core_if->hwcfg3.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg3); core_if->hwcfg4.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg4); dbg_otg("\thwcfg1=%08x\n", core_if->hwcfg1.d32); dbg_otg("\thwcfg2=%08x\n", core_if->hwcfg2.d32); dbg_otg("\thwcfg3=%08x\n", core_if->hwcfg3.d32); dbg_otg("\thwcfg4=%08x\n", core_if->hwcfg4.d32); core_if->hcfg.d32 = dwc_read_reg32(&core_if->host_if->host_global_regs->hcfg); core_if->dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg); dbg_otg("\thcfg=%08x\n", core_if->hcfg.d32); dbg_otg("\tdcfg=%08x\n", core_if->dcfg.d32); dbg_otg("\top_mode=%0x\n", core_if->hwcfg2.b.op_mode); dbg_otg("\tarch=%0x\n", core_if->hwcfg2.b.architecture); dbg_otg("\tnum_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep); dbg_otg("\tnum_host_chan=%d\n", core_if->hwcfg2.b.num_host_chan); dbg_otg("\tnonperio_tx_q_depth=0x%0x\n", core_if->hwcfg2.b.nonperio_tx_q_depth); dbg_otg("\thost_perio_tx_q_depth=0x%0x\n", core_if->hwcfg2.b.host_perio_tx_q_depth); dbg_otg("\tdev_token_q_depth=0x%0x\n", core_if->hwcfg2.b.dev_token_q_depth); dbg_otg("\tTotal FIFO SZ=%d\n", core_if->hwcfg3.b.dfifo_depth); dbg_otg("\txfer_size_cntr_width=%0x\n", core_if->hwcfg3.b.xfer_size_cntr_width); /* * Set the SRP sucess bit for FS-I2c */ core_if->srp_success = 0; core_if->srp_timer_started = 0; return core_if;}/** * This function frees the structures allocated by dwc_otg_cil_init(). * * @param[in] _core_if The core interface pointer returned from * dwc_otg_cil_init(). * */void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if){ /* Disable all interrupts */ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, 1, 0); dwc_write_reg32(&_core_if->core_global_regs->gintmsk, 0); if (_core_if->dev_if) { kfree(_core_if->dev_if); } if (_core_if->host_if) { kfree(_core_if->host_if); } kfree(_core_if);}/** * This function enables the controller's Global Interrupt in the AHB Config * register. * * @param[in] _core_if Programming view of DWC_otg controller. */extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if){ gahbcfg_data_t ahbcfg = {.d32 = 0 }; ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);}/** * This function disables the controller's Global Interrupt in the AHB Config * register. * * @param[in] _core_if Programming view of DWC_otg controller. */extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if){ gahbcfg_data_t ahbcfg = {.d32 = 0 }; ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);}/** * This function initializes the commmon interrupts, used in both * device and host modes. * * @param[in] _core_if Programming view of the DWC_otg controller * */static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * _core_if){ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; gintmsk_data_t intr_mask = {.d32 = 0 }; /* Clear any pending OTG Interrupts */ dwc_write_reg32(&global_regs->gotgint, 0xFFFFFFFF); /* Clear any pending interrupts */ dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF); /* * Enable the interrupts in the GINTMSK. */ intr_mask.b.modemismatch = 1; intr_mask.b.otgintr = 1; if (!_core_if->dma_enable) { intr_mask.b.rxstsqlvl = 1; } intr_mask.b.conidstschng = 1; intr_mask.b.wkupintr = 1; intr_mask.b.disconnect = 1; intr_mask.b.usbsuspend = 1; intr_mask.b.sessreqintr = 1; dwc_write_reg32(&global_regs->gintmsk, intr_mask.d32);}/** * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY * type. */static void init_fslspclksel(dwc_otg_core_if_t * _core_if){ uint32_t val; hcfg_data_t hcfg; if (((_core_if->hwcfg2.b.hs_phy_type == 2) && (_core_if->hwcfg2.b.fs_phy_type == 1) && (_core_if->core_params->ulpi_fs_ls)) || (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) { /* Full speed PHY */ val = DWC_HCFG_48_MHZ; } else { /* High speed PHY running at full speed or high speed */ val = DWC_HCFG_30_60_MHZ; } DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val); hcfg.d32 = dwc_read_reg32(&_core_if->host_if->host_global_regs->hcfg); hcfg.b.fslspclksel = val; dwc_write_reg32(&_core_if->host_if->host_global_regs->hcfg, hcfg.d32);}/** * Initializes the DevSpd field of the DCFG register depending on the PHY type * and the enumeration speed of the device. */static void init_devspd(dwc_otg_core_if_t * _core_if){ uint32_t val; dcfg_data_t dcfg; if (((_core_if->hwcfg2.b.hs_phy_type == 2) && (_core_if->hwcfg2.b.fs_phy_type == 1) && (_core_if->core_params->ulpi_fs_ls)) || (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) { /* Full speed PHY */ val = 0x3; } else if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) { /* High speed PHY running at full speed */ val = 0x1; } else { /* High speed PHY running at high speed */ val = 0x0; } DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); dcfg.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dcfg); dcfg.b.devspd = val; dwc_write_reg32(&_core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);}/** * This function calculates the number of IN EPS * using GHWCFG1 and GHWCFG2 registers values * * @param _pcd the pcd structure. */static uint32_t calc_num_in_eps(dwc_otg_core_if_t * _core_if){ uint32_t num_in_eps = 0; uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep; uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 3; uint32_t num_tx_fifos = _core_if->hwcfg4.b.num_in_eps; int i; for (i = 0; i < num_eps; ++i) { if (!(hwcfg1 & 0x1)) num_in_eps++; hwcfg1 >>= 2; } if (_core_if->hwcfg4.b.ded_fifo_en) { num_in_eps = (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps; } return num_in_eps;}/** * This function calculates the number of OUT EPS * using GHWCFG1 and GHWCFG2 registers values * * @param _pcd the pcd structure. */static uint32_t calc_num_out_eps(dwc_otg_core_if_t * _core_if){ uint32_t num_out_eps = 0; uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep; uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 2; int i; for (i = 0; i < num_eps; ++i) { if (!(hwcfg1 & 0x2)) num_out_eps++; hwcfg1 >>= 2; } return num_out_eps;}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -