From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marek Vasut Date: Wed, 28 Sep 2011 02:43:02 +0200 Subject: [U-Boot] [PATCH v7 4/4] Add USB support for Efika In-Reply-To: <1317162078-8041-3-git-send-email-fermata7@gmail.com> References: <1317151457-15387-1-git-send-email-fermata7@gmail.com> <1317162078-8041-1-git-send-email-fermata7@gmail.com> <1317162078-8041-3-git-send-email-fermata7@gmail.com> Message-ID: <1317170582.3390.2.camel@konomi> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de > This commit adds USB support for EfikaMX and EfikaSB. > > Signed-off-by: Jana Rapava > Signed-off-by: Marek Vasut > Cc: Remy Bohmer > Cc: Stefano Babic > --- > Changes for v2: >? ? ? - changed to proper patch > Changes for v3: >? ? ? - merged other USB patches from u-boot-pxa/efikasb >? ? ? - offset-based access changed to struct-based access >? ? ? - use {clrset,clr,set}bits_le32() calls >? ? ? - CodingStyle and naming cleanup > Changes for v4: >? ? ? ? - split into patchset >? ? ? ? - CodingStyle and naming cleanup >? ? ? ? - remove endless loops >? ? ? ? - silence compiler warnings > Changes for v5: >? ? ? ? ? ? - change order of arguments in ulpi* functions >? ? ? ? ? ? - change type of reg argument >? ? ? ? ? ? - rename offset macro > Changes for v6: >? ? ? ? ? ? ? - rebase on top of u-boot-imx/next >? ? ? ? ? ? ? - cleanup of CodingStyle and comments >? ? ? ? ? ? ? - use macro machine_is_efikasb() >? ? ? ? ? ? ? - introduce header file efika.h > Changes for v7: > ??? - add proper header to efika.h > ??? - include efika.h into efikamx.c > ??? - check return values from ulpi_wait() > >? board/efikamx/Makefile? ? ? ? ? |? ? ? 3 + >? board/efikamx/efika.h? ? ? ? ? ? |? ? 30 ++++ >? board/efikamx/efikamx-usb.c |? 397 > +++++++++++++++++++++++++++++++++++++++++++ board/efikamx/efikamx.c? ? ? > |? ? ? 3 + include/configs/efikamx.h? ? |? ? 16 ++ >? 5 files changed, 449 insertions(+), 0 deletions(-) >? create mode 100644 board/efikamx/efika.h >? create mode 100644 board/efikamx/efikamx-usb.c > Dear Jana Rapava, [...] > +u32 ulpi_wait(struct usb_ehci *ehci, u32 ulpi_bit) > +{ > +??? int timeout = ULPI_TIMEOUT; > +??? u32 tmp; > + > +??? /* Wait for the ulpi_bit to become zero. */ > +??? while (--timeout) { > +??? ??? tmp = readl(&ehci->ulpi_viewpoint); > +??? ??? if (!(tmp & ulpi_bit)) > +??? ??? ??? break; > +??? ??? WATCHDOG_RESET(); > +??? } > + > +??? if (!timeout) > +??? ??? return 0; > +??? else > +??? ??? return tmp; The logic here seems bogus, if the register is zero, this function returns zero either way. > +} > + > +void ulpi_write(struct usb_ehci *ehci, u32 reg, u32 value) > +{ > +??? if (!(readl(&ehci->ulpi_viewpoint) & ULPI_SS)) { > +??? ??? writel(ULPI_WU, &ehci->ulpi_viewpoint); > +??? ??? if (!ulpi_wait(ehci, ULPI_WU)) > +??? ??? ??? printf("ULPI wakeup timed out\n"); > +??? } > + > +??? writel(ULPI_RWRUN | ULPI_RWCTRL | > +??? ??? reg << ULPI_ADDR_SHIFT | ulpi_write_mask(value), > +??? ??? &ehci->ulpi_viewpoint); > +??? if (!ulpi_wait(ehci, ULPI_RWRUN)) > +??? ??? printf("ULPI write timed out\n"); > +} > + > +u32 ulpi_read(struct usb_ehci *ehci, u32 reg) > +{ > +??? u32 tmp; > +??? if (!(readl(&ehci->ulpi_viewpoint) & ULPI_SS)) { > +??? ??? writel(ULPI_WU, &ehci->ulpi_viewpoint); > +??? ??? if (!ulpi_wait(ehci, ULPI_WU)) > +??? ??? ??? printf("ULPI wakeup timed out\n"); > +??? } > + > +??? writel(ULPI_RWRUN | reg << ULPI_ADDR_SHIFT, &ehci->ulpi_viewpoint); > +??? tmp = ulpi_wait(ehci, ULPI_RWRUN); > +??? if (!tmp) > +??? ??? printf("ULPI read timed out\n"); > +??? return ulpi_read_mask(tmp); > +} > + > +void ulpi_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi) > +{ > +??? u32 tmp = 0; > +??? int reg, i; > + > +??? /* get ID from ULPI immediate registers */ > +??? for (reg = ULPI_ID_REGS_COUNT - 1; reg >= 0; reg--) > +??? ??? tmp |= ulpi_read(ehci, (u32)reg) << (reg * 8); Are you ignoring my comment and picking only some of them? Is the cast here necessary? > +??? /* split into vendor and product ID */ > +??? debug("Found ULPI TX, ID %04x:%04x\n", tmp >> 16, tmp & 0xffff); > + > +??? /* ULPI check integrity */ > +??? for (i = 0; i < 2; i++) { > +??? ??? ulpi_write(ehci, (u32)&ulpi->scratch_write, > +??? ??? ??? ULPI_TEST_VALUE << i); > +??? ??? tmp = ulpi_read(ehci, (u32)&ulpi->scratch_write); > + > +??? ??? if (tmp != (ULPI_TEST_VALUE << i)) { > +??? ??? ??? printf("ULPI integrity check failed\n"); > +??? ??? ??? return; > +??? ??? } > +??? } > + > +??? /* ULPI set flags */ > +??? ulpi_write(ehci, (u32)&ulpi->otg_ctrl_write, > +??? ??? ULPI_OTG_EXT_VBUS_IND | > +??? ??? ULPI_OTG_DM_PULLDOWN | ULPI_OTG_DP_PULLDOWN); > +??? ulpi_write(ehci, (u32)&ulpi->function_ctrl_write, > +??? ??? ULPI_FC_XCVR_SELECT | ULPI_FC_OPMODE_NORMAL | > +??? ??? ULPI_FC_SUSPENDM_PWRED); > +??? ulpi_write(ehci, (u32)&ulpi->iface_ctrl_write, 0); > +??? ulpi_write(ehci, (u32)&ulpi->otg_ctrl_set, > +??? ??? ULPI_OTG_DRV_VBUS | ULPI_OTG_DRV_VBUS_EXT); > + > +??? /* > +??? * NOTE: This violates USB specification, but otherwise, USB on Efika > +??? * doesn't charge VBUS and as a result, USB doesn't work. > +??? */ > +??? ulpi_write(ehci, (u32)&ulpi->otg_ctrl_set, ULPI_OTG_CHRG_VBUS); > +} > + > +/* > + * Solve the VBUS reset problem on Efika > + * by setting the CHRG_VBUS bit in the reset. > + */ > +void ehci_fixup(uint32_t *status_reg, uint32_t *reg_ref) > +{ > +??? struct usb_ehci *ehci = (struct usb_ehci *)(OTG_BASE_ADDR + > +??? ??? MX51_REGISTER_LAYOUT_LENGTH); > +??? struct mxc_ulpi_regs *ulpi = (struct mxc_ulpi_regs *)0; > + > +??? u32 tmp = ulpi_read(ehci, (u32)&ulpi->otg_ctrl_write); > +??? tmp |= ULPI_OTG_CHRG_VBUS; > +??? ulpi_write(ehci, (u32)&ulpi->otg_ctrl_write, tmp); > + > +??? /* USB 2.0 specification say 50 ms resets on root. */ Where can I read about this please? > +??? wait_ms(50); > + > +??? /* Now terminate the reset. */ > +??? *reg_ref = ehci_readl(status_reg); > +??? *reg_ref |= EHCI_PS_PE; > +} > + > +void ehci0_init(struct usb_ehci *ehci) > +{ > +??? writel(MX51_16BIT_UTMI, &ehci->portsc); > +} > + > +void ehci1_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi) > +{ > +??? mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT2); > +??? mxc_iomux_set_pad(MX51_PIN_USBH1_STP, PAD_CTL_DRV_HIGH | > +??? ??? ??? ??? PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); > +??? gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 0); > +??? udelay(1000); > +??? gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP), 1); > +??? udelay(1000); > + > +??? mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0); > +??? mxc_iomux_set_pad(MX51_PIN_USBH1_STP, USB_PAD_CONFIG); > +??? udelay(10000); > + > +??? clrbits_le32(&ehci->usbcmd, MX51_ITC_IMMEDIATE_MASK); > +??? udelay(10000); > + > +??? writel(MX51_ULPI_MODE_MASK, &ehci->portsc); > +??? udelay(10000); > + > +??? ulpi_init(ehci, ulpi); > +} > + > + remove newline > +void ehci2_init(struct usb_ehci *ehci, struct mxc_ulpi_regs *ulpi) > +{ > +??? mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT1); > +??? mxc_iomux_set_pad(MX51_PIN_EIM_A26, PAD_CTL_DRV_HIGH | > +??? ??? ??? ??? PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST); > +??? gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 0); > +??? udelay(1000); > +??? gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A26), 1); > +??? udelay(1000); > + > +??? mxc_request_iomux(MX51_PIN_EIM_A26, IOMUX_CONFIG_ALT2); > +??? mxc_iomux_set_pad(MX51_PIN_EIM_A26, USB_PAD_CONFIG); > + > +??? writel(MX51_ULPI_MODE_MASK, &ehci->portsc); > +??? udelay(10000); > + > +??? ulpi_init(ehci, ulpi); > +} > + > +int ehci_hcd_init(void) > +{ > +??? struct usb_ehci *ehci; > +??? struct mx5_usb_control_regs *mx5_usb_control_regs; > +??? struct mxc_ulpi_regs *ulpi; > + > +??? mx5_usb_control_regs = (struct mx5_usb_control_regs *)(OTG_BASE_ADDR + > +??? ??? MX5_CTRL_REGS_OFFSET); > +??? control_regs_setup(mx5_usb_control_regs); > +??? ulpi = (struct mxc_ulpi_regs *)0; > + > +??? /* Init EHCI core */ > +??? ehci = (struct usb_ehci *)(OTG_BASE_ADDR + > +??? ??? (MX51_REGISTER_LAYOUT_LENGTH * CONFIG_MXC_USB_PORT)); > +??? hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); > +??? hcor = (struct ehci_hcor *)((uint32_t) hccr + > +??? ??? ??? HC_LENGTH(ehci_readl(&hccr->cr_capbase))); > +??? setbits_le32(&ehci->usbmode, CM_HOST); > +??? setbits_le32(&ehci->control, USB_EN); > +??? > +??? /* Init iMX51 EHCI */ > +??? efika_usb_phy_reset(); > +??? efika_usb_hub_reset(); > +??? efika_usb_enable_devices(); > + > +??? switch (CONFIG_MXC_USB_PORT) { > +??? case 0: > +??? ??? ehci0_init(ehci); > +??? ??? break; > +??? case 1: > +??? ??? ehci1_init(ehci, ulpi); > +??? ??? break; > +??? case 2: > +??? ??? if (machine_is_efikasb()) { > +??? ??? ??? ehci2_init(ehci, ulpi); > +??? ??? ??? break; > +??? ??? } the break should be past the if, also you can drop the braces then. > +??? }; > + > +??? /* EfikaMX USB has issues ... */ > +??? udelay(10000); > + > +??? return 0; > +} > + > +int ehci_hcd_stop(void) > +{ > +??? return 0; > +}