Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> |
| 3 | * |
| 4 | * (C) Copyright 2009 Freescale Semiconductor, Inc. |
| 5 | * |
Wolfgang Denk | d79de1d | 2013-07-08 09:37:19 +0200 | [diff] [blame] | 6 | * SPDX-License-Identifier: GPL-2.0+ |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 7 | */ |
| 8 | |
| 9 | #include <common.h> |
| 10 | #include <usb.h> |
| 11 | #include <asm/io.h> |
| 12 | #include <asm/arch/imx-regs.h> |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 13 | #include <asm/arch/iomux-mx51.h> |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 14 | #include <asm/gpio.h> |
| 15 | #include <usb/ehci-fsl.h> |
| 16 | #include <usb/ulpi.h> |
| 17 | #include <errno.h> |
| 18 | |
Matt Sealey | af8f53b | 2012-08-22 09:25:38 +0000 | [diff] [blame] | 19 | #include "../../../drivers/usb/host/ehci.h" |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 20 | |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 21 | /* |
| 22 | * Configure the USB H1 and USB H2 IOMUX |
| 23 | */ |
| 24 | void setup_iomux_usb(void) |
| 25 | { |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 26 | static const iomux_v3_cfg_t usb_h1_pads[] = { |
| 27 | MX51_PAD_USBH1_CLK__USBH1_CLK, |
| 28 | MX51_PAD_USBH1_DIR__USBH1_DIR, |
| 29 | MX51_PAD_USBH1_STP__USBH1_STP, |
| 30 | MX51_PAD_USBH1_NXT__USBH1_NXT, |
| 31 | MX51_PAD_USBH1_DATA0__USBH1_DATA0, |
| 32 | MX51_PAD_USBH1_DATA1__USBH1_DATA1, |
| 33 | MX51_PAD_USBH1_DATA2__USBH1_DATA2, |
| 34 | MX51_PAD_USBH1_DATA3__USBH1_DATA3, |
| 35 | MX51_PAD_USBH1_DATA4__USBH1_DATA4, |
| 36 | MX51_PAD_USBH1_DATA5__USBH1_DATA5, |
| 37 | MX51_PAD_USBH1_DATA6__USBH1_DATA6, |
| 38 | MX51_PAD_USBH1_DATA7__USBH1_DATA7, |
| 39 | }; |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 40 | |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 41 | static const iomux_v3_cfg_t usb_pads[] = { |
| 42 | MX51_PAD_EIM_D27__GPIO2_9, /* USB PHY reset */ |
| 43 | MX51_PAD_GPIO1_5__GPIO1_5, /* USB HUB reset */ |
| 44 | NEW_PAD_CTRL(MX51_PAD_EIM_A22__GPIO2_16, 0), /* WIFI /EN */ |
| 45 | NEW_PAD_CTRL(MX51_PAD_EIM_A16__GPIO2_10, 0), /* WIFI RESET */ |
| 46 | NEW_PAD_CTRL(MX51_PAD_EIM_A17__GPIO2_11, 0), /* BT /EN */ |
| 47 | }; |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 48 | |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 49 | imx_iomux_v3_setup_multiple_pads(usb_h1_pads, ARRAY_SIZE(usb_h1_pads)); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 50 | |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 51 | if (machine_is_efikasb()) { |
| 52 | static const iomux_v3_cfg_t usb_h2_pads[] = { |
| 53 | MX51_PAD_EIM_A24__USBH2_CLK, |
| 54 | MX51_PAD_EIM_A25__USBH2_DIR, |
| 55 | MX51_PAD_EIM_A26__USBH2_STP, |
| 56 | MX51_PAD_EIM_A27__USBH2_NXT, |
| 57 | MX51_PAD_EIM_D16__USBH2_DATA0, |
| 58 | MX51_PAD_EIM_D17__USBH2_DATA1, |
| 59 | MX51_PAD_EIM_D18__USBH2_DATA2, |
| 60 | MX51_PAD_EIM_D19__USBH2_DATA3, |
| 61 | MX51_PAD_EIM_D20__USBH2_DATA4, |
| 62 | MX51_PAD_EIM_D21__USBH2_DATA5, |
| 63 | MX51_PAD_EIM_D22__USBH2_DATA6, |
| 64 | MX51_PAD_EIM_D23__USBH2_DATA7, |
| 65 | }; |
| 66 | |
| 67 | imx_iomux_v3_setup_multiple_pads(usb_h2_pads, |
| 68 | ARRAY_SIZE(usb_h2_pads)); |
| 69 | } |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 70 | |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 71 | imx_iomux_v3_setup_multiple_pads(usb_pads, ARRAY_SIZE(usb_pads)); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | /* |
| 75 | * Enable devices connected to USB BUSes |
| 76 | */ |
| 77 | static void efika_usb_enable_devices(void) |
| 78 | { |
| 79 | /* Enable Bluetooth */ |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 80 | gpio_direction_output(IMX_GPIO_NR(2, 11), 0); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 81 | udelay(10000); |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 82 | gpio_set_value(IMX_GPIO_NR(2, 11), 1); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 83 | |
| 84 | /* Enable WiFi */ |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 85 | gpio_direction_output(IMX_GPIO_NR(2, 16), 1); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 86 | udelay(10000); |
| 87 | |
| 88 | /* Reset the WiFi chip */ |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 89 | gpio_direction_output(IMX_GPIO_NR(2, 10), 0); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 90 | udelay(10000); |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 91 | gpio_set_value(IMX_GPIO_NR(2, 10), 1); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | /* |
| 95 | * Reset USB HUB (or HUBs on EfikaSB) |
| 96 | */ |
| 97 | static void efika_usb_hub_reset(void) |
| 98 | { |
| 99 | /* HUB reset */ |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 100 | gpio_direction_output(IMX_GPIO_NR(1, 5), 1); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 101 | udelay(1000); |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 102 | gpio_set_value(IMX_GPIO_NR(1, 5), 0); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 103 | udelay(1000); |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 104 | gpio_set_value(IMX_GPIO_NR(1, 5), 1); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 105 | } |
| 106 | |
| 107 | /* |
| 108 | * Reset USB PHY (or PHYs on EfikaSB) |
| 109 | */ |
| 110 | static void efika_usb_phy_reset(void) |
| 111 | { |
| 112 | /* SMSC 3317 PHY reset */ |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 113 | gpio_direction_output(IMX_GPIO_NR(2, 9), 0); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 114 | udelay(1000); |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 115 | gpio_set_value(IMX_GPIO_NR(2, 9), 1); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | static void efika_ehci_init(struct usb_ehci *ehci, uint32_t stp_gpio, |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 119 | iomux_v3_cfg_t stp_pad_gpio, |
| 120 | iomux_v3_cfg_t stp_pad_usb) |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 121 | { |
| 122 | int ret; |
| 123 | struct ulpi_regs *ulpi = (struct ulpi_regs *)0; |
Govindraj.R | 6645d9e | 2012-02-06 03:55:31 +0000 | [diff] [blame] | 124 | struct ulpi_viewport ulpi_vp; |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 125 | |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 126 | imx_iomux_v3_setup_pad(stp_pad_gpio); |
| 127 | gpio_direction_output(stp_gpio, 0); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 128 | udelay(1000); |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 129 | gpio_set_value(stp_gpio, 1); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 130 | udelay(1000); |
| 131 | |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 132 | imx_iomux_v3_setup_pad(stp_pad_usb); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 133 | udelay(10000); |
| 134 | |
Govindraj.R | 6645d9e | 2012-02-06 03:55:31 +0000 | [diff] [blame] | 135 | ulpi_vp.viewport_addr = (u32)&ehci->ulpi_viewpoint; |
| 136 | ulpi_vp.port_num = 0; |
| 137 | |
| 138 | ret = ulpi_init(&ulpi_vp); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 139 | if (ret) { |
| 140 | printf("Efika USB ULPI initialization failed\n"); |
| 141 | return; |
| 142 | } |
| 143 | |
| 144 | /* ULPI set flags */ |
Govindraj.R | 6645d9e | 2012-02-06 03:55:31 +0000 | [diff] [blame] | 145 | ulpi_write(&ulpi_vp, &ulpi->otg_ctrl, |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 146 | ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN | |
| 147 | ULPI_OTG_EXTVBUSIND); |
Govindraj.R | 6645d9e | 2012-02-06 03:55:31 +0000 | [diff] [blame] | 148 | ulpi_write(&ulpi_vp, &ulpi->function_ctrl, |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 149 | ULPI_FC_FULL_SPEED | ULPI_FC_OPMODE_NORMAL | |
| 150 | ULPI_FC_SUSPENDM); |
Govindraj.R | 6645d9e | 2012-02-06 03:55:31 +0000 | [diff] [blame] | 151 | ulpi_write(&ulpi_vp, &ulpi->iface_ctrl, 0); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 152 | |
| 153 | /* Set VBus */ |
Govindraj.R | 6645d9e | 2012-02-06 03:55:31 +0000 | [diff] [blame] | 154 | ulpi_write(&ulpi_vp, &ulpi->otg_ctrl_set, |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 155 | ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); |
| 156 | |
| 157 | /* |
| 158 | * Set VBusChrg |
| 159 | * |
| 160 | * NOTE: This violates USB specification, but otherwise, USB on Efika |
| 161 | * doesn't work. |
| 162 | */ |
Govindraj.R | 6645d9e | 2012-02-06 03:55:31 +0000 | [diff] [blame] | 163 | ulpi_write(&ulpi_vp, &ulpi->otg_ctrl_set, ULPI_OTG_CHRGVBUS); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 164 | } |
| 165 | |
| 166 | int board_ehci_hcd_init(int port) |
| 167 | { |
| 168 | /* Init iMX51 EHCI */ |
| 169 | efika_usb_phy_reset(); |
| 170 | efika_usb_hub_reset(); |
| 171 | efika_usb_enable_devices(); |
| 172 | |
| 173 | return 0; |
| 174 | } |
| 175 | |
| 176 | void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg) |
| 177 | { |
| 178 | uint32_t port = OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT); |
| 179 | struct usb_ehci *ehci = (struct usb_ehci *)port; |
| 180 | struct ulpi_regs *ulpi = (struct ulpi_regs *)0; |
Govindraj.R | 6645d9e | 2012-02-06 03:55:31 +0000 | [diff] [blame] | 181 | struct ulpi_viewport ulpi_vp; |
| 182 | |
| 183 | ulpi_vp.viewport_addr = (u32)&ehci->ulpi_viewpoint; |
| 184 | ulpi_vp.port_num = 0; |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 185 | |
Govindraj.R | 6645d9e | 2012-02-06 03:55:31 +0000 | [diff] [blame] | 186 | ulpi_write(&ulpi_vp, &ulpi->otg_ctrl_set, ULPI_OTG_CHRGVBUS); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 187 | |
Mike Frysinger | 60ce19a | 2012-03-05 13:47:00 +0000 | [diff] [blame] | 188 | mdelay(50); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 189 | |
| 190 | /* terminate the reset */ |
| 191 | *reg = ehci_readl(status_reg); |
| 192 | *reg |= EHCI_PS_PE; |
| 193 | } |
| 194 | |
| 195 | void board_ehci_hcd_postinit(struct usb_ehci *ehci, int port) |
| 196 | { |
| 197 | uint32_t tmp; |
| 198 | |
| 199 | if (port == 0) { |
| 200 | /* Adjust UTMI PHY frequency to 24MHz */ |
| 201 | tmp = readl(OTG_BASE_ADDR + 0x80c); |
| 202 | tmp = (tmp & ~0x3) | 0x01; |
| 203 | writel(tmp, OTG_BASE_ADDR + 0x80c); |
| 204 | } else if (port == 1) { |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 205 | efika_ehci_init(ehci, IMX_GPIO_NR(1, 27), |
| 206 | MX51_PAD_USBH1_STP__GPIO1_27, |
| 207 | MX51_PAD_USBH1_STP__USBH1_STP); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 208 | } else if ((port == 2) && machine_is_efikasb()) { |
Benoît Thébaudeau | d484f20 | 2013-05-03 10:32:28 +0000 | [diff] [blame] | 209 | efika_ehci_init(ehci, IMX_GPIO_NR(2, 20), |
| 210 | MX51_PAD_EIM_A26__GPIO2_20, |
| 211 | MX51_PAD_EIM_A26__USBH2_STP); |
Marek Vasut | f2ebfeb | 2011-06-24 21:46:07 +0200 | [diff] [blame] | 212 | } |
| 213 | |
| 214 | if (port) |
| 215 | mdelay(10); |
| 216 | } |
Matt Sealey | c4ad2cb | 2012-08-23 04:52:33 +0000 | [diff] [blame] | 217 | |
| 218 | /* |
| 219 | * Ethernet on the Smarttop is on the USB bus. Rather than give an error about |
| 220 | * "CPU Net Initialization Failed", just pass this test since no other settings |
| 221 | * are required. Smartbook doesn't have built-in Ethernet but we will let it |
| 222 | * pass anyway considering someone may have plugged in a USB stick and all |
| 223 | * they need to do is run "usb start". |
| 224 | */ |
| 225 | int board_eth_init(bd_t *bis) |
| 226 | { |
| 227 | return 0; |
| 228 | } |