📄 omap.c
字号:
*/static voidomap_udc_epn_rx(int ep){ unsigned short status; /* Check endpoint status */ status = inw(UDC_STAT_FLG); if (status & UDC_ACK) { int nbytes; struct usb_endpoint_instance *endpoint = udc_device->bus->endpoint_array + ep; nbytes = omap_read_noniso_rx_fifo(endpoint); usbd_rcv_complete_irq(endpoint, nbytes, 0); /* enable rx FIFO to prepare for next packet */ outw(UDC_Set_FIFO_En, UDC_CTRL); } else if (status & UDC_STALL) { UDCDBG("STALL on RX endpoint %d", ep); } else if (status & UDC_NAK) { UDCDBG("NAK on RX ep %d", ep); } else printk(KERN_WARNING "omap-bi: RX on ep %d with status %x", ep, status);}/* Handle TX transaction on non-ISO endpoint. * This function implements TRM Figure 14-29. * The ep argument is a physical endpoint number for a non-ISO IN endpoint * in the range 16 to 30. */static voidomap_udc_epn_tx(int ep){ unsigned short status; /* Check endpoint status */ status = inw(UDC_STAT_FLG); if (status & UDC_ACK) { struct usb_endpoint_instance *endpoint = udc_device->bus->endpoint_array + ep; /* We need to transmit a terminating zero-length packet now if * we have sent all of the data in this URB and the transfer * size was an exact multiple of the packet size. */ if (endpoint->tx_urb && (endpoint->last == endpoint->tx_packetSize) && (endpoint->tx_urb->actual_length - endpoint->sent - endpoint->last == 0)) { /* Prepare to transmit a zero-length packet. */ endpoint->sent += endpoint->last; /* write 0 bytes of data to FIFO */ omap_write_noniso_tx_fifo(endpoint); /* enable tx FIFO to start transmission */ outw(UDC_Set_FIFO_En, UDC_CTRL); } else { /* retire the data that was just sent */ usbd_tx_complete_irq(endpoint, 0); /* Check to see if we have more data ready to transmit * now. */ if (endpoint->tx_urb) { /* write data to FIFO */ omap_write_noniso_tx_fifo(endpoint); /* enable tx FIFO to start transmission */ outw(UDC_Set_FIFO_En, UDC_CTRL); } } } else if (status & UDC_STALL) { UDCDBG("STALL on TX endpoint %d", ep); } else if (status & UDC_NAK) { UDCDBG("NAK on TX endpoint %d", ep); } else printk(KERN_WARNING "omap-bi: TX on ep %d with status %x", ep, status);}#if 0static voidomap_udc_eot(void){ UDCDBG("eot NYI");}static voidomap_udc_rx_dma(void){ UDCDBG("rx dma NYI");}static voidomap_udc_tx_dma(void){ UDCDBG("tx dma NYI");}#endif/* Handle general USB interrupts and dispatch according to type. * This function implements TRM Figure 14-13. */static voidomap_udc_irq(int irq, void *dev_id, struct pt_regs *regs){ u16 irq_src = inw(UDC_IRQ_SRC); int valid_irq = 0; UDCDBG("< IRQ #%d start >- %d %x %x", udc_interrupts, irq, irq_src, inw(UDC_IRQ_EN)); if (irq_src & UDC_DS_Chg) { /* Device status changed */ omap_udc_state_changed(); valid_irq++; } if (irq_src & UDC_EP0_RX) { /* Endpoint 0 receive */ outw(UDC_EP0_RX, UDC_IRQ_SRC); /* ack interrupt */ omap_udc_ep0_rx(udc_device->bus->endpoint_array + 0); valid_irq++; } if (irq_src & UDC_EP0_TX) { /* Endpoint 0 transmit */ outw(UDC_EP0_TX, UDC_IRQ_SRC); /* ack interrupt */ omap_udc_ep0_tx(udc_device->bus->endpoint_array + 0); valid_irq++; } if (irq_src & UDC_Setup) { /* Device setup */ omap_udc_setup(udc_device->bus->endpoint_array + 0); valid_irq++; }#if 0 if (irq_src & UDC_RXn_EOT) { /* End of RX DMA transfer */ omap_udc_eot(); valid_irq++; } if (irq_src & UDC_RXn_Cnt) { /* RX DMA count (FIXME: ???) */ omap_udc_rx_dma(); valid_irq++; } if (irq_src & UDC_TXn_Done) { /* TX DMA finished */ omap_udc_tx_dma(); valid_irq++; }#endif if (!valid_irq) printk(KERN_ERR UDC_NAME ": unknown interrupt, IRQ_SRC %.4x\n", irq_src); UDCDBG("< IRQ #%d end >", udc_interrupts); udc_interrupts++;}/* This function implements TRM Figure 14-26. */static voidomap_udc_noniso_irq(int irq, void *dev_id, struct pt_regs *regs){ unsigned short epnum; unsigned short irq_src = inw(UDC_IRQ_SRC); int ep; int valid_irq = 0; UDCDBG("non-ISO IRQ, IRQ_EN %x", inw(UDC_IRQ_EN)); if (irq_src & UDC_EPn_RX) { /* Endpoint N OUT transaction */ /* Determine the endpoint number for this interrupt */ epnum = (inw(UDC_EPN_STAT) & 0x0f00) >> 8; UDCDBG("RX on ep %d", epnum); /* acknowledge interrupt */ outw(UDC_EPn_RX, UDC_IRQ_SRC); if (epnum) { /* convert epnum to physical ep */ ep = EP_ADDR_TO_PHYS_EP(USB_DIR_OUT | epnum); /* select the endpoint FIFO */ outw(UDC_EP_Sel | epnum, UDC_EP_NUM); omap_udc_epn_rx(ep); /* deselect the endpoint FIFO */ outw(epnum, UDC_EP_NUM); } valid_irq++; } if (irq_src & UDC_EPn_TX) { /* Endpoint N IN transaction */ /* Determine the endpoint number for this interrupt */ epnum = inw(UDC_EPN_STAT) & 0x000f; UDCDBG("TX on ep %d", epnum); /* acknowledge interrupt */ outw(UDC_EPn_TX, UDC_IRQ_SRC); if (epnum) { /* convert epnum to physical ep */ ep = EP_ADDR_TO_PHYS_EP(USB_DIR_IN | epnum); /* select the endpoint FIFO */ outw(UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM); omap_udc_epn_tx(ep); /* deselect the endpoint FIFO */ outw(UDC_EP_Dir | epnum, UDC_EP_NUM); } valid_irq++; } if (!valid_irq) printk(KERN_WARNING UDC_NAME ": unknown non-ISO interrupt, IRQ_SRC %.4x\n", irq_src);}/* Handle SOF USB interrupts */static voidomap_udc_sof_irq(int irq, void *dev_id, struct pt_regs *regs){ /* For now, nothing except clear interrupt */ outw(UDC_SOF_Flg, UDC_IRQ_SRC);}/* ************************************************************************** *//* ************************************************************************** *//* * Start of public functions. *//* Called by the bus interface driver to start packet transmission. */voidudc_start_in_irq(struct usb_endpoint_instance *endpoint){ unsigned short epnum = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; UDCDBG("Starting transmit on ep %d", epnum); if (endpoint->tx_urb) { /* select the endpoint FIFO */ outw(UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM); /* write data to FIFO */ omap_write_noniso_tx_fifo(endpoint); /* enable tx FIFO to start transmission */ outw(UDC_Set_FIFO_En, UDC_CTRL); /* deselect the endpoint FIFO */ outw(UDC_EP_Dir | epnum, UDC_EP_NUM); }}/* Start to initialize h/w stuff */intudc_init(void){ u16 udc_rev; static int banner_printed = 0; udc_device = NULL; UDCDBG("starting");#ifdef CONFIG_ARCH_OMAP1610#ifdef CONFIG_OMAP_H2/*set up pinout*//*USB pin group 1 configuration*/ OMAP1610_SET_FUNC_MUX_CTRL(1, FUNC_MUX_CTRL_9, 24); /*USB1.TXD W14 */ open_drain(4, PULL_DWN_CTRL_2); OMAP1610_SET_FUNC_MUX_CTRL(2, FUNC_MUX_CTRL_9, 3); /*USB1.TXEN W16 */ open_drain(29, PULL_DWN_CTRL_1); //OMAP1610_SET_FUNC_MUX_CTRL(2, FUNC_MUX_CTRL_A, 3); /*USB1.VP AA17 */ //open_drain(7, PULL_DWN_CTRL_2); OMAP1610_SET_FUNC_MUX_CTRL(4, FUNC_MUX_CTRL_9, 0); /*USB1.SEO W13 */ open_drain(28, PULL_DWN_CTRL_1); OMAP1610_SET_FUNC_MUX_CTRL(1, FUNC_MUX_CTRL_A, 9); /*USB1.RCV V15 */ open_drain(9, PULL_DWN_CTRL_2); //OMAP1610_SET_FUNC_MUX_CTRL(2,FUNC_MUX_CTRL_8,27); /*USB1.SUSP J20*/ /*not used on OMAP1610 INNOVATOR*/ //open_drain(27,PULL_DWN_CTRL_1); //OMAP1610_SET_FUNC_MUX_CTRL(2, FUNC_MUX_CTRL_A, 6); /*USB1.VM P14 */ //open_drain(8, PULL_DWN_CTRL_2); OMAP1610_SET_FUNC_MUX_CTRL(5, FUNC_MUX_CTRL_A, 12); /*USB1.SPEED R13 *//*used on OMAP1610 H2, not INNOVATOR */ open_drain(10, PULL_DWN_CTRL_2); OMAP1610_CONFIRM_MUX_SETUP(); //USB_TRANSCEIVER_CTRL.7 = 1 (CONF_USB1_UNI_R) //unidirectional vs bidirectional, set to 1 if trx mode 0 outl((inl(USB_TRANSCEIVER_CTRL) & ~(1 << 7)), USB_TRANSCEIVER_CTRL);#else //USB_TRANSCEIVER_CTRL.7 = x (CONF_USB1_UNI_R) //unidirectional vs bidirectional, set to 1 if trx mode 0 //USB_TRANSCEIVER_CTRL.8 = x (CONF_USB2_UNI_R) //unidirectional vs bidirectional, set to 1 if trx mode 0 //all other bits = 0 (enable integrated transceiver, DP, DM, pull-downs on both) outl((inl(USB_TRANSCEIVER_CTRL) & ((1 << 7) | (1 << 8))), USB_TRANSCEIVER_CTRL);#endif /*set up USB Host without OTG function. OTG registers still must be configured */ //RESET_CONTROL.0 = 1 (CONF_OCP_RESET_R) //page oct03.448 //RESET_CONTROL.2 = 1 (CONF_ARMIO_RESET_R) outl(inl(RESET_CONTROL) | 5, RESET_CONTROL); //ARM_RSTCT2.0 = 1(PER_EN) outl(inl(ARM_RSTCT2) | 1, ARM_RSTCT2); //CLOCK_CTRL_REG.5 = 0 (DIS_USB_PVCI_CLK) //CLOCK_CTRL_REG.4 = 1 (USB_MCLK_EN) outl((inl(CLOCK_CTRL_REG) & ~(1 << 5)), CLOCK_CTRL_REG); outl((inl(CLOCK_CTRL_REG) | (1 << 4)), CLOCK_CTRL_REG); //SOFT_REQ_REG.8 = 1 (SOFT_USB_OTG_DPLL_REQ) //SOFT_REQ_REG.4 = 1 (USB_REQ_EN) //USB Client HW DPLL req //SOFT_REQ_REG.3 = 1 (SOFT_USB_REQ) //SOFT_REQ_REG.0 = 1 (SOFT_DPLL_REQ) //ULPD_PLL clock req outl((inl(SOFT_REQ_REG) | (1 << 0) | (1 << 3) | (1 << 4) | (1 << 8)), SOFT_REQ_REG); //SOFT_DISABLE_REQ_REG.3 = 0 (DIS_PERIPH_REQ) outl((inl(SOFT_DISABLE_REQ_REG) & ~(1 << 3)), SOFT_DISABLE_REQ_REG); //MOD_CONF_CTRL_0.17 = 0 (CONF_MOD_USB_W2FC_VBUS_MODE_R) //VBUS Detection via AA2/via FUNC_MUX_CTRL_0(19-18) outl((inl(MOD_CONF_CTRL_0) & ~(1 << 17)), MOD_CONF_CTRL_0); //? OTG_SYSCON_1.1 = 1 (SOFT_RST) //? OTG_SYSCON_1.2 == 1 ? (RESET_DONE) //OTG_SYSCON_1.15 = 0 (OTG_IDLE_EN) //OTG_SYSCON_1.13 = 0 (DEV_IDLE_EN) //user choice //OTG_SYSCON_1.1 = 0 (SOFT_RST)#ifdef CONFIG_OMAP_H2 //OTG_SYSCON_1.26-24 = 0 (USB2_TRXMODE) //user choice //OTG_SYSCON_1.22-20 = 2 (USB1_TRXMODE) //user choice //OTG_SYSCON_1.18-16 = 0 (USB0_TRXMODE) //user choice outl((2 << 20), OTG_SYSCON_1);#else //OTG_SYSCON_1.26-24 = x (USB2_TRXMODE) //user choice //OTG_SYSCON_1.22-20 = x (USB1_TRXMODE) //user choice //OTG_SYSCON_1.18-16 = 3 (USB0_TRXMODE) //user choice outl((inl(OTG_SYSCON_1) & ((7 << 20) | (7 << 24))), OTG_SYSCON_1); outl((inl(OTG_SYSCON_1) | (3 << 16)), OTG_SYSCON_1);#endif //OTG_CTRL.18 = 0 (BSESSVLD) //1 = host attached (VBUS present) outl(0, OTG_CTRL); //OTG_SYSCON_2.31 = 0 (OTG_EN) //OTG_SYSCON_2.30 = 1 (USBx_SYNCHRO) //OTG_SYSCON_2.29 = 0 (OTG_MST16) //OTG_SYSCON_2.28 = 0 (SRP_GPDATA) //OTG_SYSCON_2.27 = 0 (SRP_GPDVBUS) //OTG_SYSCON_2.26-24 = 0 (SRP_GPUVBUS) //OTG_SYSCON_2.22-20 = 0 (A_WAIT_RISE) //OTG_SYSCON_2.18-16 = 4 (B_ASE0_BRST) //OTG_SYSCON_2.14 = 0 (SRP_DPW) //OTG_SYSCON_2.13 = 0 (SRP_DATA) //OTG_SYSCON_2.12 = 0 (SRP_VBUS) //OTG_SYSCON_2.10 = 0 (OTG_PADEN) //OTG_SYSCON_2.9 = 0 (HMC_PADEN) //OTG_SYSCON_2.7 = 0 (HMC_TTLSPEED) //user choice //OTG_SYSCON_2.6 = 0 (HMC_TTLATTACH) //user choice#ifdef CONFIG_OMAP_H2 //OTG_SYSCON_2.8 = 0 (UHOST_EN) //user choice //OTG_SYSCON_2.5-0 = 3 (HMC_MODE) //user choice outl((1 << 30) | (4 << 16) | 3, OTG_SYSCON_2);#else //OTG_SYSCON_2.8 = x (UHOST_EN) //user choice //OTG_SYSCON_2.5-0 = 4 (HMC_MODE) //user choice outl((inl(OTG_SYSCON_2) & ((1 << 30) | (4 << 16) | (1 << 8) | 4)), OTG_SYSCON_2); outl((inl(OTG_SYSCON_2) | (1 << 30) | (4 << 16) | 4), OTG_SYSCON_2);#endif //OTG_IRQ_EN = 0 outl(0, OTG_IRQ_EN); //OTG_SYSCON_1.15 = 1 (OTG_IDLE_EN) //to reduce power consumption //outl(inl(OTG_SYSCON_1)|(1<<15),OTG_SYSCON_1); //if enabled, usbserial looses some incoming data#else /*old OMAP1510 configuration */ /* Check peripheral reset. Must be 1 to make sure MPU TIPB peripheral reset is inactive */ UDCREG(ARM_RSTCT2); /* Set and check clock control. * We might ought to be using the clock control API to do * this instead of fiddling with the clock registers directly * here. */ outw((1 << 4) | (1 << 5), CLOCK_CTRL); UDCREG(CLOCK_CTRL); /* Set and check APLL */ outw(0x0008, APLL_CTRL); UDCREG(APLL_CTRL); /* Set and check DPLL */ outw(0x2210, DPLL_CTRL); UDCREG(DPLL_CTRL); /* Set and check SOFT */ outw((1 << 4) | (1 << 3) | 1, SOFT_REQ); /* Short delay to wait for DPLL */ mdelay(1);#endif /* Print banner with device revision */ udc_rev = inw(UDC_REV) & 0xff; if (!banner_printed) { banner_printed = 1; printk(KERN_INFO "TI OMAP1510/1610 USB function module rev %d.%d\n", udc_rev >> 4, udc_rev); } /* The VBUS_MODE bit selects whether VBUS detection is done via * software (1) or hardware (0). When software detection is * selected, VBUS_CTRL selects whether USB is not connected (0) * or connected (1). */ outl(inl(FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0); outl(inl(FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0); UDCREGL(FUNC_MUX_CTRL_0); /* We'll assume that our firmware has properly initialized our * I/O pin multiplexing configuration so we don't need to fuss * with it here. Keeping this sort of thing out of the driver * makes it more likely that the driver will work without * modification on OMAP boards that might have the USB function * module pinned out differently than the Innovator. */#if 0 /* FUNC_MUX_CTRL_D bits 5:3 select whether OMAP pin W4 is the * USB.PUEN signal (000) or the USB.CLK0 signal (001). Pin W4 * is used for the USB.PUEN signal on the Innovator. */ outl(inl(FUNC_MUX_CTRL_D) & ~(7 << 3), FUNC_MUX_CTRL_D);#endif UDCREGL(FUNC_MUX_CTRL_D); /* * At this point, device is ready for configuration... */ UDCDBG("disable USB interrupts"); outw(0, UDC_IRQ_EN); UDCREG(UDC_IRQ_EN); UDCDBG("disable USB DMA"); outw(0, UDC_DMA_IRQ_EN); UDCREG(UDC_DMA_IRQ_EN); UDCDBG("initialize SYSCON1"); outw(UDC_SYSCON1_INIT, UDC_SYSCON1); UDCREG(UDC_SYSCON1); return 0;}/* Stall endpoint */voidudc_stall_ep(unsigned int ep){ int ep_addr = PHYS_EP_TO_EP_ADDR(ep); int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; unsigned long flags; UDCDBG("stall ep %d", ep); /* REVISIT? * The OMAP TRM section 14.2.4.2 says we must check that the FIFO * is empty before halting the endpoint. The current implementation * doesn't check that the FIFO is empty. */ local_irq_save(flags); if (!ep_num) { outw(UDC_Stall_Cmd, UDC_SYSCON2); } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { if (inw(UDC_EP_RX(ep_num)) & UDC_EPn_RX_Valid) { /* we have a valid rx endpoint, so halt it */ outw(ep_num, UDC_EP_NUM); outw(UDC_Set_Halt, UDC_CTRL); } } else { if (inw(UDC_EP_TX(ep_num)) & UDC_EPn_TX_Valid) { /* we have a valid tx endpoint, so halt it */ outw(ep_num | UDC_EP_Dir, UDC_EP_NUM); outw(UDC_Set_Halt, UDC_CTRL); } } local_irq_restore(flags);}/* Reset endpoint */voidudc_reset_ep(unsigned int ep){ int ep_addr = PHYS_EP_TO_EP_ADDR(ep); int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; unsigned long flags; UDCDBG("reset ep %d", ep); local_irq_save(flags); if (!ep_num) { /* control endpoint 0 can't be reset */ } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { UDCDBG("UDC_EP_RX(%d) = 0x%04x", ep_num, inw(UDC_EP_RX(ep_num))); if (inw(UDC_EP_RX(ep_num)) & UDC_EPn_RX_Valid) { /* we have a valid rx endpoint, so reset it */ outw(ep_num | UDC_EP_Sel, UDC_EP_NUM); outw(UDC_Reset_EP, UDC_CTRL); outw(ep_num, UDC_EP_NUM); UDCDBG("OUT endpoint %d reset", ep_num); } } else { UDCDBG("UDC_EP_TX(%d) = 0x%04x", ep_num, inw(UDC_EP_TX(ep_num))); /* Resetting of tx endpoints seems to be causing the USB function * module to fail, which causes problems when the driver is * uninstalled. We'll skip resetting tx endpoints for now until * we figure out what the problem is.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -