11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2dd0cdd88STony Lindgren /* 34d94b4a2SAaro Koskinen * Platform level USB initialization for FS USB OTG controller on omap1 4dd0cdd88STony Lindgren * 5dd0cdd88STony Lindgren * Copyright (C) 2004 Texas Instruments, Inc. 6dd0cdd88STony Lindgren */ 7dd0cdd88STony Lindgren 8dd0cdd88STony Lindgren #include <linux/module.h> 9dd0cdd88STony Lindgren #include <linux/kernel.h> 10dd0cdd88STony Lindgren #include <linux/init.h> 11dd0cdd88STony Lindgren #include <linux/platform_device.h> 1216fee29bSChristoph Hellwig #include <linux/dma-map-ops.h> 13dd0cdd88STony Lindgren #include <linux/io.h> 1494ad8aacSArnd Bergmann #include <linux/delay.h> 15dd0cdd88STony Lindgren 16dd0cdd88STony Lindgren #include <asm/irq.h> 17dd0cdd88STony Lindgren 1870c494c3STony Lindgren #include <mach/mux.h> 19b924b204STony Lindgren 20*e8e77e97SArnd Bergmann #include "usb.h" 21dd0cdd88STony Lindgren 22d3645d39SPaul Walmsley #include "common.h" 23d3645d39SPaul Walmsley 24dd0cdd88STony Lindgren /* These routines should handle the standard chip-specific modes 25dd0cdd88STony Lindgren * for usb0/1/2 ports, covering basic mux and transceiver setup. 26dd0cdd88STony Lindgren * 27dd0cdd88STony Lindgren * Some board-*.c files will need to set up additional mux options, 28dd0cdd88STony Lindgren * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup. 29dd0cdd88STony Lindgren */ 30dd0cdd88STony Lindgren 31dd0cdd88STony Lindgren /* TESTED ON: 32dd0cdd88STony Lindgren * - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables 33dd0cdd88STony Lindgren * - 5912 OSK OHCI (with usb0 standard-A), standard A-to-B cables 34dd0cdd88STony Lindgren * - 5912 OSK UDC, with *nonstandard* A-to-A cable 35dd0cdd88STony Lindgren * - 1510 Innovator UDC with bundled usb0 cable 36dd0cdd88STony Lindgren * - 1510 Innovator OHCI with bundled usb1/usb2 cable 37dd0cdd88STony Lindgren * - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS 38dd0cdd88STony Lindgren * - 1710 custom development board using alternate pin group 39dd0cdd88STony Lindgren * - 1710 H3 (with usb1 mini-AB) using standard Mini-B or OTG cables 40dd0cdd88STony Lindgren */ 41dd0cdd88STony Lindgren 42dd0cdd88STony Lindgren #define INT_USB_IRQ_GEN IH2_BASE + 20 43dd0cdd88STony Lindgren #define INT_USB_IRQ_NISO IH2_BASE + 30 44dd0cdd88STony Lindgren #define INT_USB_IRQ_ISO IH2_BASE + 29 45dd0cdd88STony Lindgren #define INT_USB_IRQ_HGEN INT_USB_HHC_1 46dd0cdd88STony Lindgren #define INT_USB_IRQ_OTG IH2_BASE + 8 47dd0cdd88STony Lindgren 48b924b204STony Lindgren #ifdef CONFIG_ARCH_OMAP_OTG 49b924b204STony Lindgren 50bde49e59SAaro Koskinen static void __init 51b924b204STony Lindgren omap_otg_init(struct omap_usb_config *config) 52b924b204STony Lindgren { 53b924b204STony Lindgren u32 syscon; 54b924b204STony Lindgren int alt_pingroup = 0; 554d94b4a2SAaro Koskinen u16 w; 56b924b204STony Lindgren 57b924b204STony Lindgren /* NOTE: no bus or clock setup (yet?) */ 58b924b204STony Lindgren 59b924b204STony Lindgren syscon = omap_readl(OTG_SYSCON_1) & 0xffff; 60b924b204STony Lindgren if (!(syscon & OTG_RESET_DONE)) 61b924b204STony Lindgren pr_debug("USB resets not complete?\n"); 62b924b204STony Lindgren 63b924b204STony Lindgren //omap_writew(0, OTG_IRQ_EN); 64b924b204STony Lindgren 65b924b204STony Lindgren /* pin muxing and transceiver pinouts */ 66b924b204STony Lindgren if (config->pins[0] > 2) /* alt pingroup 2 */ 67b924b204STony Lindgren alt_pingroup = 1; 68b924b204STony Lindgren syscon |= config->usb0_init(config->pins[0], is_usb0_device(config)); 69b924b204STony Lindgren syscon |= config->usb1_init(config->pins[1]); 70b924b204STony Lindgren syscon |= config->usb2_init(config->pins[2], alt_pingroup); 71b924b204STony Lindgren pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1)); 72b924b204STony Lindgren omap_writel(syscon, OTG_SYSCON_1); 73b924b204STony Lindgren 74b924b204STony Lindgren syscon = config->hmc_mode; 75b924b204STony Lindgren syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */; 76b924b204STony Lindgren #ifdef CONFIG_USB_OTG 77b924b204STony Lindgren if (config->otg) 78b924b204STony Lindgren syscon |= OTG_EN; 79b924b204STony Lindgren #endif 80b924b204STony Lindgren pr_debug("USB_TRANSCEIVER_CTRL = %03x\n", 81b924b204STony Lindgren omap_readl(USB_TRANSCEIVER_CTRL)); 82b924b204STony Lindgren pr_debug("OTG_SYSCON_2 = %08x\n", omap_readl(OTG_SYSCON_2)); 83b924b204STony Lindgren omap_writel(syscon, OTG_SYSCON_2); 84b924b204STony Lindgren 85b924b204STony Lindgren printk("USB: hmc %d", config->hmc_mode); 86b924b204STony Lindgren if (!alt_pingroup) 877e600cadSAaro Koskinen pr_cont(", usb2 alt %d wires", config->pins[2]); 88b924b204STony Lindgren else if (config->pins[0]) 897e600cadSAaro Koskinen pr_cont(", usb0 %d wires%s", config->pins[0], 90b924b204STony Lindgren is_usb0_device(config) ? " (dev)" : ""); 91b924b204STony Lindgren if (config->pins[1]) 927e600cadSAaro Koskinen pr_cont(", usb1 %d wires", config->pins[1]); 93b924b204STony Lindgren if (!alt_pingroup && config->pins[2]) 947e600cadSAaro Koskinen pr_cont(", usb2 %d wires", config->pins[2]); 95b924b204STony Lindgren if (config->otg) 967e600cadSAaro Koskinen pr_cont(", Mini-AB on usb%d", config->otg - 1); 977e600cadSAaro Koskinen pr_cont("\n"); 98b924b204STony Lindgren 99b924b204STony Lindgren /* leave USB clocks/controllers off until needed */ 100b924b204STony Lindgren w = omap_readw(ULPD_SOFT_REQ); 101b924b204STony Lindgren w &= ~SOFT_USB_CLK_REQ; 102b924b204STony Lindgren omap_writew(w, ULPD_SOFT_REQ); 103b924b204STony Lindgren 104b924b204STony Lindgren w = omap_readw(ULPD_CLOCK_CTRL); 105b924b204STony Lindgren w &= ~USB_MCLK_EN; 106b924b204STony Lindgren w |= DIS_USB_PVCI_CLK; 107b924b204STony Lindgren omap_writew(w, ULPD_CLOCK_CTRL); 1084d94b4a2SAaro Koskinen 109b924b204STony Lindgren syscon = omap_readl(OTG_SYSCON_1); 110b924b204STony Lindgren syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN; 111b924b204STony Lindgren 1120345a1e3SAaro Koskinen #if IS_ENABLED(CONFIG_USB_OMAP) 113b924b204STony Lindgren if (config->otg || config->register_dev) { 114b924b204STony Lindgren struct platform_device *udc_device = config->udc_device; 115b924b204STony Lindgren int status; 116b924b204STony Lindgren 117b924b204STony Lindgren syscon &= ~DEV_IDLE_EN; 118b924b204STony Lindgren udc_device->dev.platform_data = config; 119b924b204STony Lindgren status = platform_device_register(udc_device); 120b924b204STony Lindgren if (status) 121b924b204STony Lindgren pr_debug("can't register UDC device, %d\n", status); 122b924b204STony Lindgren } 123b924b204STony Lindgren #endif 124b924b204STony Lindgren 125fcebddb9SJavier Martinez Canillas #if IS_ENABLED(CONFIG_USB_OHCI_HCD) 126b924b204STony Lindgren if (config->otg || config->register_host) { 127b924b204STony Lindgren struct platform_device *ohci_device = config->ohci_device; 128b924b204STony Lindgren int status; 129b924b204STony Lindgren 130b924b204STony Lindgren syscon &= ~HST_IDLE_EN; 131b924b204STony Lindgren ohci_device->dev.platform_data = config; 132b924b204STony Lindgren status = platform_device_register(ohci_device); 133b924b204STony Lindgren if (status) 134b924b204STony Lindgren pr_debug("can't register OHCI device, %d\n", status); 135b924b204STony Lindgren } 136b924b204STony Lindgren #endif 137b924b204STony Lindgren 138b924b204STony Lindgren #ifdef CONFIG_USB_OTG 139b924b204STony Lindgren if (config->otg) { 140b924b204STony Lindgren struct platform_device *otg_device = config->otg_device; 141b924b204STony Lindgren int status; 142b924b204STony Lindgren 143b924b204STony Lindgren syscon &= ~OTG_IDLE_EN; 144b924b204STony Lindgren otg_device->dev.platform_data = config; 145b924b204STony Lindgren status = platform_device_register(otg_device); 146b924b204STony Lindgren if (status) 147b924b204STony Lindgren pr_debug("can't register OTG device, %d\n", status); 148b924b204STony Lindgren } 149b924b204STony Lindgren #endif 150b924b204STony Lindgren pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1)); 151b924b204STony Lindgren omap_writel(syscon, OTG_SYSCON_1); 152b924b204STony Lindgren } 153b924b204STony Lindgren 154b924b204STony Lindgren #else 155bde49e59SAaro Koskinen static void omap_otg_init(struct omap_usb_config *config) {} 156b924b204STony Lindgren #endif 157b924b204STony Lindgren 1580345a1e3SAaro Koskinen #if IS_ENABLED(CONFIG_USB_OMAP) 159dd0cdd88STony Lindgren 160dd0cdd88STony Lindgren static struct resource udc_resources[] = { 161dd0cdd88STony Lindgren /* order is significant! */ 162dd0cdd88STony Lindgren { /* registers */ 163dd0cdd88STony Lindgren .start = UDC_BASE, 164dd0cdd88STony Lindgren .end = UDC_BASE + 0xff, 165dd0cdd88STony Lindgren .flags = IORESOURCE_MEM, 166dd0cdd88STony Lindgren }, { /* general IRQ */ 167dd0cdd88STony Lindgren .start = INT_USB_IRQ_GEN, 168dd0cdd88STony Lindgren .flags = IORESOURCE_IRQ, 169dd0cdd88STony Lindgren }, { /* PIO IRQ */ 170dd0cdd88STony Lindgren .start = INT_USB_IRQ_NISO, 171dd0cdd88STony Lindgren .flags = IORESOURCE_IRQ, 172dd0cdd88STony Lindgren }, { /* SOF IRQ */ 173dd0cdd88STony Lindgren .start = INT_USB_IRQ_ISO, 174dd0cdd88STony Lindgren .flags = IORESOURCE_IRQ, 175dd0cdd88STony Lindgren }, 176dd0cdd88STony Lindgren }; 177dd0cdd88STony Lindgren 178dd0cdd88STony Lindgren static u64 udc_dmamask = ~(u32)0; 179dd0cdd88STony Lindgren 180dd0cdd88STony Lindgren static struct platform_device udc_device = { 181dd0cdd88STony Lindgren .name = "omap_udc", 182dd0cdd88STony Lindgren .id = -1, 183dd0cdd88STony Lindgren .dev = { 184dd0cdd88STony Lindgren .dma_mask = &udc_dmamask, 185dd0cdd88STony Lindgren .coherent_dma_mask = 0xffffffff, 186dd0cdd88STony Lindgren }, 187dd0cdd88STony Lindgren .num_resources = ARRAY_SIZE(udc_resources), 188dd0cdd88STony Lindgren .resource = udc_resources, 189dd0cdd88STony Lindgren }; 190dd0cdd88STony Lindgren 191dd0cdd88STony Lindgren static inline void udc_device_init(struct omap_usb_config *pdata) 192dd0cdd88STony Lindgren { 193dd0cdd88STony Lindgren /* IRQ numbers for omap7xx */ 194dd0cdd88STony Lindgren if(cpu_is_omap7xx()) { 195dd0cdd88STony Lindgren udc_resources[1].start = INT_7XX_USB_GENI; 196dd0cdd88STony Lindgren udc_resources[2].start = INT_7XX_USB_NON_ISO; 197dd0cdd88STony Lindgren udc_resources[3].start = INT_7XX_USB_ISO; 198dd0cdd88STony Lindgren } 199dd0cdd88STony Lindgren pdata->udc_device = &udc_device; 200dd0cdd88STony Lindgren } 201dd0cdd88STony Lindgren 202dd0cdd88STony Lindgren #else 203dd0cdd88STony Lindgren 204dd0cdd88STony Lindgren static inline void udc_device_init(struct omap_usb_config *pdata) 205dd0cdd88STony Lindgren { 206dd0cdd88STony Lindgren } 207dd0cdd88STony Lindgren 208dd0cdd88STony Lindgren #endif 209dd0cdd88STony Lindgren 210dd0cdd88STony Lindgren /* The dmamask must be set for OHCI to work */ 211dd0cdd88STony Lindgren static u64 ohci_dmamask = ~(u32)0; 212dd0cdd88STony Lindgren 213dd0cdd88STony Lindgren static struct resource ohci_resources[] = { 214dd0cdd88STony Lindgren { 215dd0cdd88STony Lindgren .start = OMAP_OHCI_BASE, 216dd0cdd88STony Lindgren .end = OMAP_OHCI_BASE + 0xff, 217dd0cdd88STony Lindgren .flags = IORESOURCE_MEM, 218dd0cdd88STony Lindgren }, 219dd0cdd88STony Lindgren { 220dd0cdd88STony Lindgren .start = INT_USB_IRQ_HGEN, 221dd0cdd88STony Lindgren .flags = IORESOURCE_IRQ, 222dd0cdd88STony Lindgren }, 223dd0cdd88STony Lindgren }; 224dd0cdd88STony Lindgren 225dd0cdd88STony Lindgren static struct platform_device ohci_device = { 226dd0cdd88STony Lindgren .name = "ohci", 227dd0cdd88STony Lindgren .id = -1, 228dd0cdd88STony Lindgren .dev = { 229dd0cdd88STony Lindgren .dma_mask = &ohci_dmamask, 230dd0cdd88STony Lindgren .coherent_dma_mask = 0xffffffff, 231dd0cdd88STony Lindgren }, 232dd0cdd88STony Lindgren .num_resources = ARRAY_SIZE(ohci_resources), 233dd0cdd88STony Lindgren .resource = ohci_resources, 234dd0cdd88STony Lindgren }; 235dd0cdd88STony Lindgren 236dd0cdd88STony Lindgren static inline void ohci_device_init(struct omap_usb_config *pdata) 237dd0cdd88STony Lindgren { 23894ad8aacSArnd Bergmann if (!IS_ENABLED(CONFIG_USB_OHCI_HCD)) 23994ad8aacSArnd Bergmann return; 24094ad8aacSArnd Bergmann 241dd0cdd88STony Lindgren if (cpu_is_omap7xx()) 242dd0cdd88STony Lindgren ohci_resources[1].start = INT_7XX_USB_HHC_1; 243dd0cdd88STony Lindgren pdata->ohci_device = &ohci_device; 244d3645d39SPaul Walmsley pdata->ocpi_enable = &ocpi_enable; 245dd0cdd88STony Lindgren } 246dd0cdd88STony Lindgren 247dd0cdd88STony Lindgren #if defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG) 248dd0cdd88STony Lindgren 249dd0cdd88STony Lindgren static struct resource otg_resources[] = { 250dd0cdd88STony Lindgren /* order is significant! */ 251dd0cdd88STony Lindgren { 252dd0cdd88STony Lindgren .start = OTG_BASE, 253dd0cdd88STony Lindgren .end = OTG_BASE + 0xff, 254dd0cdd88STony Lindgren .flags = IORESOURCE_MEM, 255dd0cdd88STony Lindgren }, { 256dd0cdd88STony Lindgren .start = INT_USB_IRQ_OTG, 257dd0cdd88STony Lindgren .flags = IORESOURCE_IRQ, 258dd0cdd88STony Lindgren }, 259dd0cdd88STony Lindgren }; 260dd0cdd88STony Lindgren 261dd0cdd88STony Lindgren static struct platform_device otg_device = { 262dd0cdd88STony Lindgren .name = "omap_otg", 263dd0cdd88STony Lindgren .id = -1, 264dd0cdd88STony Lindgren .num_resources = ARRAY_SIZE(otg_resources), 265dd0cdd88STony Lindgren .resource = otg_resources, 266dd0cdd88STony Lindgren }; 267dd0cdd88STony Lindgren 268dd0cdd88STony Lindgren static inline void otg_device_init(struct omap_usb_config *pdata) 269dd0cdd88STony Lindgren { 270dd0cdd88STony Lindgren if (cpu_is_omap7xx()) 271dd0cdd88STony Lindgren otg_resources[1].start = INT_7XX_USB_OTG; 272dd0cdd88STony Lindgren pdata->otg_device = &otg_device; 273dd0cdd88STony Lindgren } 274dd0cdd88STony Lindgren 275dd0cdd88STony Lindgren #else 276dd0cdd88STony Lindgren 277dd0cdd88STony Lindgren static inline void otg_device_init(struct omap_usb_config *pdata) 278dd0cdd88STony Lindgren { 279dd0cdd88STony Lindgren } 280dd0cdd88STony Lindgren 281dd0cdd88STony Lindgren #endif 282dd0cdd88STony Lindgren 283eba36d77SPaul Walmsley static u32 __init omap1_usb0_init(unsigned nwires, unsigned is_device) 284dd0cdd88STony Lindgren { 285dd0cdd88STony Lindgren u32 syscon1 = 0; 286dd0cdd88STony Lindgren 287dd0cdd88STony Lindgren if (nwires == 0) { 288dd0cdd88STony Lindgren if (!cpu_is_omap15xx()) { 289dd0cdd88STony Lindgren u32 l; 290dd0cdd88STony Lindgren 291dd0cdd88STony Lindgren /* pulldown D+/D- */ 292dd0cdd88STony Lindgren l = omap_readl(USB_TRANSCEIVER_CTRL); 293dd0cdd88STony Lindgren l &= ~(3 << 1); 294dd0cdd88STony Lindgren omap_writel(l, USB_TRANSCEIVER_CTRL); 295dd0cdd88STony Lindgren } 296dd0cdd88STony Lindgren return 0; 297dd0cdd88STony Lindgren } 298dd0cdd88STony Lindgren 299dd0cdd88STony Lindgren if (is_device) { 300dd0cdd88STony Lindgren if (cpu_is_omap7xx()) { 301dd0cdd88STony Lindgren omap_cfg_reg(AA17_7XX_USB_DM); 302dd0cdd88STony Lindgren omap_cfg_reg(W16_7XX_USB_PU_EN); 303dd0cdd88STony Lindgren omap_cfg_reg(W17_7XX_USB_VBUSI); 304dd0cdd88STony Lindgren omap_cfg_reg(W18_7XX_USB_DMCK_OUT); 305dd0cdd88STony Lindgren omap_cfg_reg(W19_7XX_USB_DCRST); 306dd0cdd88STony Lindgren } else 307dd0cdd88STony Lindgren omap_cfg_reg(W4_USB_PUEN); 308dd0cdd88STony Lindgren } 309dd0cdd88STony Lindgren 310dd0cdd88STony Lindgren if (nwires == 2) { 311dd0cdd88STony Lindgren u32 l; 312dd0cdd88STony Lindgren 313dd0cdd88STony Lindgren // omap_cfg_reg(P9_USB_DP); 314dd0cdd88STony Lindgren // omap_cfg_reg(R8_USB_DM); 315dd0cdd88STony Lindgren 316dd0cdd88STony Lindgren if (cpu_is_omap15xx()) { 317dd0cdd88STony Lindgren /* This works on 1510-Innovator */ 318dd0cdd88STony Lindgren return 0; 319dd0cdd88STony Lindgren } 320dd0cdd88STony Lindgren 321dd0cdd88STony Lindgren /* NOTES: 322dd0cdd88STony Lindgren * - peripheral should configure VBUS detection! 323dd0cdd88STony Lindgren * - only peripherals may use the internal D+/D- pulldowns 324dd0cdd88STony Lindgren * - OTG support on this port not yet written 325dd0cdd88STony Lindgren */ 326dd0cdd88STony Lindgren 327dd0cdd88STony Lindgren /* Don't do this for omap7xx -- it causes USB to not work correctly */ 328dd0cdd88STony Lindgren if (!cpu_is_omap7xx()) { 329dd0cdd88STony Lindgren l = omap_readl(USB_TRANSCEIVER_CTRL); 330dd0cdd88STony Lindgren l &= ~(7 << 4); 331dd0cdd88STony Lindgren if (!is_device) 332dd0cdd88STony Lindgren l |= (3 << 1); 333dd0cdd88STony Lindgren omap_writel(l, USB_TRANSCEIVER_CTRL); 334dd0cdd88STony Lindgren } 335dd0cdd88STony Lindgren 336dd0cdd88STony Lindgren return 3 << 16; 337dd0cdd88STony Lindgren } 338dd0cdd88STony Lindgren 339dd0cdd88STony Lindgren /* alternate pin config, external transceiver */ 340dd0cdd88STony Lindgren if (cpu_is_omap15xx()) { 341dd0cdd88STony Lindgren printk(KERN_ERR "no usb0 alt pin config on 15xx\n"); 342dd0cdd88STony Lindgren return 0; 343dd0cdd88STony Lindgren } 344dd0cdd88STony Lindgren 345dd0cdd88STony Lindgren omap_cfg_reg(V6_USB0_TXD); 346dd0cdd88STony Lindgren omap_cfg_reg(W9_USB0_TXEN); 347dd0cdd88STony Lindgren omap_cfg_reg(W5_USB0_SE0); 348dd0cdd88STony Lindgren if (nwires != 3) 349dd0cdd88STony Lindgren omap_cfg_reg(Y5_USB0_RCV); 350dd0cdd88STony Lindgren 351dd0cdd88STony Lindgren /* NOTE: SPEED and SUSP aren't configured here. OTG hosts 352dd0cdd88STony Lindgren * may be able to use I2C requests to set those bits along 353dd0cdd88STony Lindgren * with VBUS switching and overcurrent detection. 354dd0cdd88STony Lindgren */ 355dd0cdd88STony Lindgren 356dd0cdd88STony Lindgren if (nwires != 6) { 357dd0cdd88STony Lindgren u32 l; 358dd0cdd88STony Lindgren 359dd0cdd88STony Lindgren l = omap_readl(USB_TRANSCEIVER_CTRL); 360dd0cdd88STony Lindgren l &= ~CONF_USB2_UNI_R; 361dd0cdd88STony Lindgren omap_writel(l, USB_TRANSCEIVER_CTRL); 362dd0cdd88STony Lindgren } 363dd0cdd88STony Lindgren 364dd0cdd88STony Lindgren switch (nwires) { 365dd0cdd88STony Lindgren case 3: 366dd0cdd88STony Lindgren syscon1 = 2; 367dd0cdd88STony Lindgren break; 368dd0cdd88STony Lindgren case 4: 369dd0cdd88STony Lindgren syscon1 = 1; 370dd0cdd88STony Lindgren break; 371dd0cdd88STony Lindgren case 6: 372dd0cdd88STony Lindgren syscon1 = 3; 373dd0cdd88STony Lindgren { 374dd0cdd88STony Lindgren u32 l; 375dd0cdd88STony Lindgren 376dd0cdd88STony Lindgren omap_cfg_reg(AA9_USB0_VP); 377dd0cdd88STony Lindgren omap_cfg_reg(R9_USB0_VM); 378dd0cdd88STony Lindgren l = omap_readl(USB_TRANSCEIVER_CTRL); 379dd0cdd88STony Lindgren l |= CONF_USB2_UNI_R; 380dd0cdd88STony Lindgren omap_writel(l, USB_TRANSCEIVER_CTRL); 381dd0cdd88STony Lindgren } 382dd0cdd88STony Lindgren break; 383dd0cdd88STony Lindgren default: 384dd0cdd88STony Lindgren printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", 385dd0cdd88STony Lindgren 0, nwires); 386dd0cdd88STony Lindgren } 387dd0cdd88STony Lindgren 388dd0cdd88STony Lindgren return syscon1 << 16; 389dd0cdd88STony Lindgren } 390dd0cdd88STony Lindgren 391eba36d77SPaul Walmsley static u32 __init omap1_usb1_init(unsigned nwires) 392dd0cdd88STony Lindgren { 393dd0cdd88STony Lindgren u32 syscon1 = 0; 394dd0cdd88STony Lindgren 395dd0cdd88STony Lindgren if (!cpu_is_omap15xx() && nwires != 6) { 396dd0cdd88STony Lindgren u32 l; 397dd0cdd88STony Lindgren 398dd0cdd88STony Lindgren l = omap_readl(USB_TRANSCEIVER_CTRL); 399dd0cdd88STony Lindgren l &= ~CONF_USB1_UNI_R; 400dd0cdd88STony Lindgren omap_writel(l, USB_TRANSCEIVER_CTRL); 401dd0cdd88STony Lindgren } 402dd0cdd88STony Lindgren if (nwires == 0) 403dd0cdd88STony Lindgren return 0; 404dd0cdd88STony Lindgren 405dd0cdd88STony Lindgren /* external transceiver */ 406dd0cdd88STony Lindgren omap_cfg_reg(USB1_TXD); 407dd0cdd88STony Lindgren omap_cfg_reg(USB1_TXEN); 408dd0cdd88STony Lindgren if (nwires != 3) 409dd0cdd88STony Lindgren omap_cfg_reg(USB1_RCV); 410dd0cdd88STony Lindgren 411dd0cdd88STony Lindgren if (cpu_is_omap15xx()) { 412dd0cdd88STony Lindgren omap_cfg_reg(USB1_SEO); 413dd0cdd88STony Lindgren omap_cfg_reg(USB1_SPEED); 414dd0cdd88STony Lindgren // SUSP 415dd0cdd88STony Lindgren } else if (cpu_is_omap1610() || cpu_is_omap5912()) { 416dd0cdd88STony Lindgren omap_cfg_reg(W13_1610_USB1_SE0); 417dd0cdd88STony Lindgren omap_cfg_reg(R13_1610_USB1_SPEED); 418dd0cdd88STony Lindgren // SUSP 419dd0cdd88STony Lindgren } else if (cpu_is_omap1710()) { 420dd0cdd88STony Lindgren omap_cfg_reg(R13_1710_USB1_SE0); 421dd0cdd88STony Lindgren // SUSP 422dd0cdd88STony Lindgren } else { 423dd0cdd88STony Lindgren pr_debug("usb%d cpu unrecognized\n", 1); 424dd0cdd88STony Lindgren return 0; 425dd0cdd88STony Lindgren } 426dd0cdd88STony Lindgren 427dd0cdd88STony Lindgren switch (nwires) { 428dd0cdd88STony Lindgren case 2: 429dd0cdd88STony Lindgren goto bad; 430dd0cdd88STony Lindgren case 3: 431dd0cdd88STony Lindgren syscon1 = 2; 432dd0cdd88STony Lindgren break; 433dd0cdd88STony Lindgren case 4: 434dd0cdd88STony Lindgren syscon1 = 1; 435dd0cdd88STony Lindgren break; 436dd0cdd88STony Lindgren case 6: 437dd0cdd88STony Lindgren syscon1 = 3; 438dd0cdd88STony Lindgren omap_cfg_reg(USB1_VP); 439dd0cdd88STony Lindgren omap_cfg_reg(USB1_VM); 440dd0cdd88STony Lindgren if (!cpu_is_omap15xx()) { 441dd0cdd88STony Lindgren u32 l; 442dd0cdd88STony Lindgren 443dd0cdd88STony Lindgren l = omap_readl(USB_TRANSCEIVER_CTRL); 444dd0cdd88STony Lindgren l |= CONF_USB1_UNI_R; 445dd0cdd88STony Lindgren omap_writel(l, USB_TRANSCEIVER_CTRL); 446dd0cdd88STony Lindgren } 447dd0cdd88STony Lindgren break; 448dd0cdd88STony Lindgren default: 449dd0cdd88STony Lindgren bad: 450dd0cdd88STony Lindgren printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", 451dd0cdd88STony Lindgren 1, nwires); 452dd0cdd88STony Lindgren } 453dd0cdd88STony Lindgren 454dd0cdd88STony Lindgren return syscon1 << 20; 455dd0cdd88STony Lindgren } 456dd0cdd88STony Lindgren 457eba36d77SPaul Walmsley static u32 __init omap1_usb2_init(unsigned nwires, unsigned alt_pingroup) 458dd0cdd88STony Lindgren { 459dd0cdd88STony Lindgren u32 syscon1 = 0; 460dd0cdd88STony Lindgren 461dd0cdd88STony Lindgren /* NOTE omap1 erratum: must leave USB2_UNI_R set if usb0 in use */ 462dd0cdd88STony Lindgren if (alt_pingroup || nwires == 0) 463dd0cdd88STony Lindgren return 0; 464dd0cdd88STony Lindgren 465dd0cdd88STony Lindgren if (!cpu_is_omap15xx() && nwires != 6) { 466dd0cdd88STony Lindgren u32 l; 467dd0cdd88STony Lindgren 468dd0cdd88STony Lindgren l = omap_readl(USB_TRANSCEIVER_CTRL); 469dd0cdd88STony Lindgren l &= ~CONF_USB2_UNI_R; 470dd0cdd88STony Lindgren omap_writel(l, USB_TRANSCEIVER_CTRL); 471dd0cdd88STony Lindgren } 472dd0cdd88STony Lindgren 473dd0cdd88STony Lindgren /* external transceiver */ 474dd0cdd88STony Lindgren if (cpu_is_omap15xx()) { 475dd0cdd88STony Lindgren omap_cfg_reg(USB2_TXD); 476dd0cdd88STony Lindgren omap_cfg_reg(USB2_TXEN); 477dd0cdd88STony Lindgren omap_cfg_reg(USB2_SEO); 478dd0cdd88STony Lindgren if (nwires != 3) 479dd0cdd88STony Lindgren omap_cfg_reg(USB2_RCV); 480dd0cdd88STony Lindgren /* there is no USB2_SPEED */ 481dd0cdd88STony Lindgren } else if (cpu_is_omap16xx()) { 482dd0cdd88STony Lindgren omap_cfg_reg(V6_USB2_TXD); 483dd0cdd88STony Lindgren omap_cfg_reg(W9_USB2_TXEN); 484dd0cdd88STony Lindgren omap_cfg_reg(W5_USB2_SE0); 485dd0cdd88STony Lindgren if (nwires != 3) 486dd0cdd88STony Lindgren omap_cfg_reg(Y5_USB2_RCV); 487dd0cdd88STony Lindgren // FIXME omap_cfg_reg(USB2_SPEED); 488dd0cdd88STony Lindgren } else { 489dd0cdd88STony Lindgren pr_debug("usb%d cpu unrecognized\n", 1); 490dd0cdd88STony Lindgren return 0; 491dd0cdd88STony Lindgren } 492dd0cdd88STony Lindgren 493dd0cdd88STony Lindgren // omap_cfg_reg(USB2_SUSP); 494dd0cdd88STony Lindgren 495dd0cdd88STony Lindgren switch (nwires) { 496dd0cdd88STony Lindgren case 2: 497dd0cdd88STony Lindgren goto bad; 498dd0cdd88STony Lindgren case 3: 499dd0cdd88STony Lindgren syscon1 = 2; 500dd0cdd88STony Lindgren break; 501dd0cdd88STony Lindgren case 4: 502dd0cdd88STony Lindgren syscon1 = 1; 503dd0cdd88STony Lindgren break; 504dd0cdd88STony Lindgren case 5: 505dd0cdd88STony Lindgren goto bad; 506dd0cdd88STony Lindgren case 6: 507dd0cdd88STony Lindgren syscon1 = 3; 508dd0cdd88STony Lindgren if (cpu_is_omap15xx()) { 509dd0cdd88STony Lindgren omap_cfg_reg(USB2_VP); 510dd0cdd88STony Lindgren omap_cfg_reg(USB2_VM); 511dd0cdd88STony Lindgren } else { 512dd0cdd88STony Lindgren u32 l; 513dd0cdd88STony Lindgren 514dd0cdd88STony Lindgren omap_cfg_reg(AA9_USB2_VP); 515dd0cdd88STony Lindgren omap_cfg_reg(R9_USB2_VM); 516dd0cdd88STony Lindgren l = omap_readl(USB_TRANSCEIVER_CTRL); 517dd0cdd88STony Lindgren l |= CONF_USB2_UNI_R; 518dd0cdd88STony Lindgren omap_writel(l, USB_TRANSCEIVER_CTRL); 519dd0cdd88STony Lindgren } 520dd0cdd88STony Lindgren break; 521dd0cdd88STony Lindgren default: 522dd0cdd88STony Lindgren bad: 523dd0cdd88STony Lindgren printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", 524dd0cdd88STony Lindgren 2, nwires); 525dd0cdd88STony Lindgren } 526dd0cdd88STony Lindgren 527dd0cdd88STony Lindgren return syscon1 << 24; 528dd0cdd88STony Lindgren } 529dd0cdd88STony Lindgren 530dd0cdd88STony Lindgren #ifdef CONFIG_ARCH_OMAP15XX 53194ad8aacSArnd Bergmann /* OMAP-1510 OHCI has its own MMU for DMA */ 53294ad8aacSArnd Bergmann #define OMAP1510_LB_MEMSIZE 32 /* Should be same as SDRAM size */ 53394ad8aacSArnd Bergmann #define OMAP1510_LB_CLOCK_DIV 0xfffec10c 53494ad8aacSArnd Bergmann #define OMAP1510_LB_MMU_CTL 0xfffec208 53594ad8aacSArnd Bergmann #define OMAP1510_LB_MMU_LCK 0xfffec224 53694ad8aacSArnd Bergmann #define OMAP1510_LB_MMU_LD_TLB 0xfffec228 53794ad8aacSArnd Bergmann #define OMAP1510_LB_MMU_CAM_H 0xfffec22c 53894ad8aacSArnd Bergmann #define OMAP1510_LB_MMU_CAM_L 0xfffec230 53994ad8aacSArnd Bergmann #define OMAP1510_LB_MMU_RAM_H 0xfffec234 54094ad8aacSArnd Bergmann #define OMAP1510_LB_MMU_RAM_L 0xfffec238 54194ad8aacSArnd Bergmann 54294ad8aacSArnd Bergmann /* 54394ad8aacSArnd Bergmann * Bus address is physical address, except for OMAP-1510 Local Bus. 54494ad8aacSArnd Bergmann * OMAP-1510 bus address is translated into a Local Bus address if the 54594ad8aacSArnd Bergmann * OMAP bus type is lbus. 54694ad8aacSArnd Bergmann */ 54794ad8aacSArnd Bergmann #define OMAP1510_LB_OFFSET UL(0x30000000) 54894ad8aacSArnd Bergmann 54994ad8aacSArnd Bergmann /* 55094ad8aacSArnd Bergmann * OMAP-1510 specific Local Bus clock on/off 55194ad8aacSArnd Bergmann */ 55294ad8aacSArnd Bergmann static int omap_1510_local_bus_power(int on) 55394ad8aacSArnd Bergmann { 55494ad8aacSArnd Bergmann if (on) { 55594ad8aacSArnd Bergmann omap_writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL); 55694ad8aacSArnd Bergmann udelay(200); 55794ad8aacSArnd Bergmann } else { 55894ad8aacSArnd Bergmann omap_writel(0, OMAP1510_LB_MMU_CTL); 55994ad8aacSArnd Bergmann } 56094ad8aacSArnd Bergmann 56194ad8aacSArnd Bergmann return 0; 56294ad8aacSArnd Bergmann } 56394ad8aacSArnd Bergmann 56494ad8aacSArnd Bergmann /* 56594ad8aacSArnd Bergmann * OMAP-1510 specific Local Bus initialization 56694ad8aacSArnd Bergmann * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE. 56794ad8aacSArnd Bergmann * See also arch/mach-omap/memory.h for __virt_to_dma() and 56894ad8aacSArnd Bergmann * __dma_to_virt() which need to match with the physical 56994ad8aacSArnd Bergmann * Local Bus address below. 57094ad8aacSArnd Bergmann */ 57194ad8aacSArnd Bergmann static int omap_1510_local_bus_init(void) 57294ad8aacSArnd Bergmann { 57394ad8aacSArnd Bergmann unsigned int tlb; 57494ad8aacSArnd Bergmann unsigned long lbaddr, physaddr; 57594ad8aacSArnd Bergmann 57694ad8aacSArnd Bergmann omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, 57794ad8aacSArnd Bergmann OMAP1510_LB_CLOCK_DIV); 57894ad8aacSArnd Bergmann 57994ad8aacSArnd Bergmann /* Configure the Local Bus MMU table */ 58094ad8aacSArnd Bergmann for (tlb = 0; tlb < OMAP1510_LB_MEMSIZE; tlb++) { 58194ad8aacSArnd Bergmann lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET; 58294ad8aacSArnd Bergmann physaddr = tlb * 0x00100000 + PHYS_OFFSET; 58394ad8aacSArnd Bergmann omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); 58494ad8aacSArnd Bergmann omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, 58594ad8aacSArnd Bergmann OMAP1510_LB_MMU_CAM_L); 58694ad8aacSArnd Bergmann omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); 58794ad8aacSArnd Bergmann omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); 58894ad8aacSArnd Bergmann omap_writel(tlb << 4, OMAP1510_LB_MMU_LCK); 58994ad8aacSArnd Bergmann omap_writel(0x1, OMAP1510_LB_MMU_LD_TLB); 59094ad8aacSArnd Bergmann } 59194ad8aacSArnd Bergmann 59294ad8aacSArnd Bergmann /* Enable the walking table */ 59394ad8aacSArnd Bergmann omap_writel(omap_readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL); 59494ad8aacSArnd Bergmann udelay(200); 59594ad8aacSArnd Bergmann 59694ad8aacSArnd Bergmann return 0; 59794ad8aacSArnd Bergmann } 59894ad8aacSArnd Bergmann 59994ad8aacSArnd Bergmann static void omap_1510_local_bus_reset(void) 60094ad8aacSArnd Bergmann { 60194ad8aacSArnd Bergmann omap_1510_local_bus_power(1); 60294ad8aacSArnd Bergmann omap_1510_local_bus_init(); 60394ad8aacSArnd Bergmann } 604dd0cdd88STony Lindgren 605dd0cdd88STony Lindgren /* ULPD_DPLL_CTRL */ 606dd0cdd88STony Lindgren #define DPLL_IOB (1 << 13) 607dd0cdd88STony Lindgren #define DPLL_PLL_ENABLE (1 << 4) 608dd0cdd88STony Lindgren #define DPLL_LOCK (1 << 0) 609dd0cdd88STony Lindgren 610dd0cdd88STony Lindgren /* ULPD_APLL_CTRL */ 611dd0cdd88STony Lindgren #define APLL_NDPLL_SWITCH (1 << 0) 612dd0cdd88STony Lindgren 613dd0cdd88STony Lindgren static void __init omap_1510_usb_init(struct omap_usb_config *config) 614dd0cdd88STony Lindgren { 615dd0cdd88STony Lindgren unsigned int val; 616dd0cdd88STony Lindgren u16 w; 617dd0cdd88STony Lindgren 618dd0cdd88STony Lindgren config->usb0_init(config->pins[0], is_usb0_device(config)); 619dd0cdd88STony Lindgren config->usb1_init(config->pins[1]); 620dd0cdd88STony Lindgren config->usb2_init(config->pins[2], 0); 621dd0cdd88STony Lindgren 622dd0cdd88STony Lindgren val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1); 623dd0cdd88STony Lindgren val |= (config->hmc_mode << 1); 624dd0cdd88STony Lindgren omap_writel(val, MOD_CONF_CTRL_0); 625dd0cdd88STony Lindgren 626dd0cdd88STony Lindgren printk("USB: hmc %d", config->hmc_mode); 627dd0cdd88STony Lindgren if (config->pins[0]) 6287e600cadSAaro Koskinen pr_cont(", usb0 %d wires%s", config->pins[0], 629dd0cdd88STony Lindgren is_usb0_device(config) ? " (dev)" : ""); 630dd0cdd88STony Lindgren if (config->pins[1]) 6317e600cadSAaro Koskinen pr_cont(", usb1 %d wires", config->pins[1]); 632dd0cdd88STony Lindgren if (config->pins[2]) 6337e600cadSAaro Koskinen pr_cont(", usb2 %d wires", config->pins[2]); 6347e600cadSAaro Koskinen pr_cont("\n"); 635dd0cdd88STony Lindgren 636dd0cdd88STony Lindgren /* use DPLL for 48 MHz function clock */ 637dd0cdd88STony Lindgren pr_debug("APLL %04x DPLL %04x REQ %04x\n", omap_readw(ULPD_APLL_CTRL), 638dd0cdd88STony Lindgren omap_readw(ULPD_DPLL_CTRL), omap_readw(ULPD_SOFT_REQ)); 639dd0cdd88STony Lindgren 640dd0cdd88STony Lindgren w = omap_readw(ULPD_APLL_CTRL); 641dd0cdd88STony Lindgren w &= ~APLL_NDPLL_SWITCH; 642dd0cdd88STony Lindgren omap_writew(w, ULPD_APLL_CTRL); 643dd0cdd88STony Lindgren 644dd0cdd88STony Lindgren w = omap_readw(ULPD_DPLL_CTRL); 645dd0cdd88STony Lindgren w |= DPLL_IOB | DPLL_PLL_ENABLE; 646dd0cdd88STony Lindgren omap_writew(w, ULPD_DPLL_CTRL); 647dd0cdd88STony Lindgren 648dd0cdd88STony Lindgren w = omap_readw(ULPD_SOFT_REQ); 649dd0cdd88STony Lindgren w |= SOFT_UDC_REQ | SOFT_DPLL_REQ; 650dd0cdd88STony Lindgren omap_writew(w, ULPD_SOFT_REQ); 651dd0cdd88STony Lindgren 652dd0cdd88STony Lindgren while (!(omap_readw(ULPD_DPLL_CTRL) & DPLL_LOCK)) 653dd0cdd88STony Lindgren cpu_relax(); 654dd0cdd88STony Lindgren 6550345a1e3SAaro Koskinen #if IS_ENABLED(CONFIG_USB_OMAP) 656dd0cdd88STony Lindgren if (config->register_dev) { 657dd0cdd88STony Lindgren int status; 658dd0cdd88STony Lindgren 659dd0cdd88STony Lindgren udc_device.dev.platform_data = config; 660dd0cdd88STony Lindgren status = platform_device_register(&udc_device); 661dd0cdd88STony Lindgren if (status) 662dd0cdd88STony Lindgren pr_debug("can't register UDC device, %d\n", status); 663dd0cdd88STony Lindgren /* udc driver gates 48MHz by D+ pullup */ 664dd0cdd88STony Lindgren } 665dd0cdd88STony Lindgren #endif 666dd0cdd88STony Lindgren 66794ad8aacSArnd Bergmann if (IS_ENABLED(CONFIG_USB_OHCI_HCD) && config->register_host) { 668dd0cdd88STony Lindgren int status; 669dd0cdd88STony Lindgren 670dd0cdd88STony Lindgren ohci_device.dev.platform_data = config; 67194ad8aacSArnd Bergmann dma_direct_set_offset(&ohci_device.dev, PHYS_OFFSET, 67294ad8aacSArnd Bergmann OMAP1510_LB_OFFSET, (u64)-1); 673dd0cdd88STony Lindgren status = platform_device_register(&ohci_device); 674dd0cdd88STony Lindgren if (status) 675dd0cdd88STony Lindgren pr_debug("can't register OHCI device, %d\n", status); 676dd0cdd88STony Lindgren /* hcd explicitly gates 48MHz */ 67794ad8aacSArnd Bergmann 67894ad8aacSArnd Bergmann config->lb_reset = omap_1510_local_bus_reset; 679dd0cdd88STony Lindgren } 680dd0cdd88STony Lindgren } 681dd0cdd88STony Lindgren 682dd0cdd88STony Lindgren #else 683dd0cdd88STony Lindgren static inline void omap_1510_usb_init(struct omap_usb_config *config) {} 684dd0cdd88STony Lindgren #endif 685dd0cdd88STony Lindgren 68607fd296dSAaro Koskinen void __init omap1_usb_init(struct omap_usb_config *_pdata) 687dd0cdd88STony Lindgren { 68807fd296dSAaro Koskinen struct omap_usb_config *pdata; 68907fd296dSAaro Koskinen 69007fd296dSAaro Koskinen pdata = kmemdup(_pdata, sizeof(*pdata), GFP_KERNEL); 69107fd296dSAaro Koskinen if (!pdata) 69207fd296dSAaro Koskinen return; 69307fd296dSAaro Koskinen 694dd0cdd88STony Lindgren pdata->usb0_init = omap1_usb0_init; 695dd0cdd88STony Lindgren pdata->usb1_init = omap1_usb1_init; 696dd0cdd88STony Lindgren pdata->usb2_init = omap1_usb2_init; 697dd0cdd88STony Lindgren udc_device_init(pdata); 698dd0cdd88STony Lindgren ohci_device_init(pdata); 699dd0cdd88STony Lindgren otg_device_init(pdata); 700dd0cdd88STony Lindgren 701dd0cdd88STony Lindgren if (cpu_is_omap7xx() || cpu_is_omap16xx()) 702dd0cdd88STony Lindgren omap_otg_init(pdata); 703dd0cdd88STony Lindgren else if (cpu_is_omap15xx()) 704dd0cdd88STony Lindgren omap_1510_usb_init(pdata); 705dd0cdd88STony Lindgren else 706dd0cdd88STony Lindgren printk(KERN_ERR "USB: No init for your chip yet\n"); 707dd0cdd88STony Lindgren } 708