162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Platform level USB initialization for FS USB OTG controller on omap1 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004 Texas Instruments, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci#include <linux/dma-map-ops.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/soc/ti/omap1-io.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <asm/irq.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "hardware.h" 2062306a36Sopenharmony_ci#include "mux.h" 2162306a36Sopenharmony_ci#include "usb.h" 2262306a36Sopenharmony_ci#include "common.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* These routines should handle the standard chip-specific modes 2562306a36Sopenharmony_ci * for usb0/1/2 ports, covering basic mux and transceiver setup. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Some board-*.c files will need to set up additional mux options, 2862306a36Sopenharmony_ci * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* TESTED ON: 3262306a36Sopenharmony_ci * - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables 3362306a36Sopenharmony_ci * - 5912 OSK OHCI (with usb0 standard-A), standard A-to-B cables 3462306a36Sopenharmony_ci * - 5912 OSK UDC, with *nonstandard* A-to-A cable 3562306a36Sopenharmony_ci * - 1510 Innovator UDC with bundled usb0 cable 3662306a36Sopenharmony_ci * - 1510 Innovator OHCI with bundled usb1/usb2 cable 3762306a36Sopenharmony_ci * - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS 3862306a36Sopenharmony_ci * - 1710 custom development board using alternate pin group 3962306a36Sopenharmony_ci * - 1710 H3 (with usb1 mini-AB) using standard Mini-B or OTG cables 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define INT_USB_IRQ_GEN IH2_BASE + 20 4362306a36Sopenharmony_ci#define INT_USB_IRQ_NISO IH2_BASE + 30 4462306a36Sopenharmony_ci#define INT_USB_IRQ_ISO IH2_BASE + 29 4562306a36Sopenharmony_ci#define INT_USB_IRQ_HGEN INT_USB_HHC_1 4662306a36Sopenharmony_ci#define INT_USB_IRQ_OTG IH2_BASE + 8 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP_OTG 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic void __init 5162306a36Sopenharmony_ciomap_otg_init(struct omap_usb_config *config) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci u32 syscon; 5462306a36Sopenharmony_ci int alt_pingroup = 0; 5562306a36Sopenharmony_ci u16 w; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* NOTE: no bus or clock setup (yet?) */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci syscon = omap_readl(OTG_SYSCON_1) & 0xffff; 6062306a36Sopenharmony_ci if (!(syscon & OTG_RESET_DONE)) 6162306a36Sopenharmony_ci pr_debug("USB resets not complete?\n"); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci //omap_writew(0, OTG_IRQ_EN); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* pin muxing and transceiver pinouts */ 6662306a36Sopenharmony_ci if (config->pins[0] > 2) /* alt pingroup 2 */ 6762306a36Sopenharmony_ci alt_pingroup = 1; 6862306a36Sopenharmony_ci syscon |= config->usb0_init(config->pins[0], is_usb0_device(config)); 6962306a36Sopenharmony_ci syscon |= config->usb1_init(config->pins[1]); 7062306a36Sopenharmony_ci syscon |= config->usb2_init(config->pins[2], alt_pingroup); 7162306a36Sopenharmony_ci pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1)); 7262306a36Sopenharmony_ci omap_writel(syscon, OTG_SYSCON_1); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci syscon = config->hmc_mode; 7562306a36Sopenharmony_ci syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */; 7662306a36Sopenharmony_ci#ifdef CONFIG_USB_OTG 7762306a36Sopenharmony_ci if (config->otg) 7862306a36Sopenharmony_ci syscon |= OTG_EN; 7962306a36Sopenharmony_ci#endif 8062306a36Sopenharmony_ci pr_debug("USB_TRANSCEIVER_CTRL = %03x\n", 8162306a36Sopenharmony_ci omap_readl(USB_TRANSCEIVER_CTRL)); 8262306a36Sopenharmony_ci pr_debug("OTG_SYSCON_2 = %08x\n", omap_readl(OTG_SYSCON_2)); 8362306a36Sopenharmony_ci omap_writel(syscon, OTG_SYSCON_2); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci printk("USB: hmc %d", config->hmc_mode); 8662306a36Sopenharmony_ci if (!alt_pingroup) 8762306a36Sopenharmony_ci pr_cont(", usb2 alt %d wires", config->pins[2]); 8862306a36Sopenharmony_ci else if (config->pins[0]) 8962306a36Sopenharmony_ci pr_cont(", usb0 %d wires%s", config->pins[0], 9062306a36Sopenharmony_ci is_usb0_device(config) ? " (dev)" : ""); 9162306a36Sopenharmony_ci if (config->pins[1]) 9262306a36Sopenharmony_ci pr_cont(", usb1 %d wires", config->pins[1]); 9362306a36Sopenharmony_ci if (!alt_pingroup && config->pins[2]) 9462306a36Sopenharmony_ci pr_cont(", usb2 %d wires", config->pins[2]); 9562306a36Sopenharmony_ci if (config->otg) 9662306a36Sopenharmony_ci pr_cont(", Mini-AB on usb%d", config->otg - 1); 9762306a36Sopenharmony_ci pr_cont("\n"); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* leave USB clocks/controllers off until needed */ 10062306a36Sopenharmony_ci w = omap_readw(ULPD_SOFT_REQ); 10162306a36Sopenharmony_ci w &= ~SOFT_USB_CLK_REQ; 10262306a36Sopenharmony_ci omap_writew(w, ULPD_SOFT_REQ); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci w = omap_readw(ULPD_CLOCK_CTRL); 10562306a36Sopenharmony_ci w &= ~USB_MCLK_EN; 10662306a36Sopenharmony_ci w |= DIS_USB_PVCI_CLK; 10762306a36Sopenharmony_ci omap_writew(w, ULPD_CLOCK_CTRL); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci syscon = omap_readl(OTG_SYSCON_1); 11062306a36Sopenharmony_ci syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_OMAP) 11362306a36Sopenharmony_ci if (config->otg || config->register_dev) { 11462306a36Sopenharmony_ci struct platform_device *udc_device = config->udc_device; 11562306a36Sopenharmony_ci int status; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci syscon &= ~DEV_IDLE_EN; 11862306a36Sopenharmony_ci udc_device->dev.platform_data = config; 11962306a36Sopenharmony_ci status = platform_device_register(udc_device); 12062306a36Sopenharmony_ci if (status) 12162306a36Sopenharmony_ci pr_debug("can't register UDC device, %d\n", status); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci#endif 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_OHCI_HCD) 12662306a36Sopenharmony_ci if (config->otg || config->register_host) { 12762306a36Sopenharmony_ci struct platform_device *ohci_device = config->ohci_device; 12862306a36Sopenharmony_ci int status; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci syscon &= ~HST_IDLE_EN; 13162306a36Sopenharmony_ci ohci_device->dev.platform_data = config; 13262306a36Sopenharmony_ci status = platform_device_register(ohci_device); 13362306a36Sopenharmony_ci if (status) 13462306a36Sopenharmony_ci pr_debug("can't register OHCI device, %d\n", status); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci#endif 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#ifdef CONFIG_USB_OTG 13962306a36Sopenharmony_ci if (config->otg) { 14062306a36Sopenharmony_ci struct platform_device *otg_device = config->otg_device; 14162306a36Sopenharmony_ci int status; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci syscon &= ~OTG_IDLE_EN; 14462306a36Sopenharmony_ci otg_device->dev.platform_data = config; 14562306a36Sopenharmony_ci status = platform_device_register(otg_device); 14662306a36Sopenharmony_ci if (status) 14762306a36Sopenharmony_ci pr_debug("can't register OTG device, %d\n", status); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci#endif 15062306a36Sopenharmony_ci pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1)); 15162306a36Sopenharmony_ci omap_writel(syscon, OTG_SYSCON_1); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#else 15562306a36Sopenharmony_cistatic void omap_otg_init(struct omap_usb_config *config) {} 15662306a36Sopenharmony_ci#endif 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_OMAP) 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic struct resource udc_resources[] = { 16162306a36Sopenharmony_ci /* order is significant! */ 16262306a36Sopenharmony_ci { /* registers */ 16362306a36Sopenharmony_ci .start = UDC_BASE, 16462306a36Sopenharmony_ci .end = UDC_BASE + 0xff, 16562306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 16662306a36Sopenharmony_ci }, { /* general IRQ */ 16762306a36Sopenharmony_ci .start = INT_USB_IRQ_GEN, 16862306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 16962306a36Sopenharmony_ci }, { /* PIO IRQ */ 17062306a36Sopenharmony_ci .start = INT_USB_IRQ_NISO, 17162306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 17262306a36Sopenharmony_ci }, { /* SOF IRQ */ 17362306a36Sopenharmony_ci .start = INT_USB_IRQ_ISO, 17462306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 17562306a36Sopenharmony_ci }, 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic u64 udc_dmamask = ~(u32)0; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic struct platform_device udc_device = { 18162306a36Sopenharmony_ci .name = "omap_udc", 18262306a36Sopenharmony_ci .id = -1, 18362306a36Sopenharmony_ci .dev = { 18462306a36Sopenharmony_ci .dma_mask = &udc_dmamask, 18562306a36Sopenharmony_ci .coherent_dma_mask = 0xffffffff, 18662306a36Sopenharmony_ci }, 18762306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(udc_resources), 18862306a36Sopenharmony_ci .resource = udc_resources, 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic inline void udc_device_init(struct omap_usb_config *pdata) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci pdata->udc_device = &udc_device; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#else 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic inline void udc_device_init(struct omap_usb_config *pdata) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci#endif 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* The dmamask must be set for OHCI to work */ 20562306a36Sopenharmony_cistatic u64 ohci_dmamask = ~(u32)0; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic struct resource ohci_resources[] = { 20862306a36Sopenharmony_ci { 20962306a36Sopenharmony_ci .start = OMAP_OHCI_BASE, 21062306a36Sopenharmony_ci .end = OMAP_OHCI_BASE + 0xff, 21162306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 21262306a36Sopenharmony_ci }, 21362306a36Sopenharmony_ci { 21462306a36Sopenharmony_ci .start = INT_USB_IRQ_HGEN, 21562306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 21662306a36Sopenharmony_ci }, 21762306a36Sopenharmony_ci}; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic struct platform_device ohci_device = { 22062306a36Sopenharmony_ci .name = "ohci", 22162306a36Sopenharmony_ci .id = -1, 22262306a36Sopenharmony_ci .dev = { 22362306a36Sopenharmony_ci .dma_mask = &ohci_dmamask, 22462306a36Sopenharmony_ci .coherent_dma_mask = 0xffffffff, 22562306a36Sopenharmony_ci }, 22662306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(ohci_resources), 22762306a36Sopenharmony_ci .resource = ohci_resources, 22862306a36Sopenharmony_ci}; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic inline void ohci_device_init(struct omap_usb_config *pdata) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_USB_OHCI_HCD)) 23362306a36Sopenharmony_ci return; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci pdata->ohci_device = &ohci_device; 23662306a36Sopenharmony_ci pdata->ocpi_enable = &ocpi_enable; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci#if defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG) 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic struct resource otg_resources[] = { 24262306a36Sopenharmony_ci /* order is significant! */ 24362306a36Sopenharmony_ci { 24462306a36Sopenharmony_ci .start = OTG_BASE, 24562306a36Sopenharmony_ci .end = OTG_BASE + 0xff, 24662306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 24762306a36Sopenharmony_ci }, { 24862306a36Sopenharmony_ci .start = INT_USB_IRQ_OTG, 24962306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 25062306a36Sopenharmony_ci }, 25162306a36Sopenharmony_ci}; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic struct platform_device otg_device = { 25462306a36Sopenharmony_ci .name = "omap_otg", 25562306a36Sopenharmony_ci .id = -1, 25662306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(otg_resources), 25762306a36Sopenharmony_ci .resource = otg_resources, 25862306a36Sopenharmony_ci}; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic inline void otg_device_init(struct omap_usb_config *pdata) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci pdata->otg_device = &otg_device; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci#else 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic inline void otg_device_init(struct omap_usb_config *pdata) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci#endif 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic u32 __init omap1_usb0_init(unsigned nwires, unsigned is_device) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci u32 syscon1 = 0; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (nwires == 0) { 27862306a36Sopenharmony_ci if (!cpu_is_omap15xx()) { 27962306a36Sopenharmony_ci u32 l; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* pulldown D+/D- */ 28262306a36Sopenharmony_ci l = omap_readl(USB_TRANSCEIVER_CTRL); 28362306a36Sopenharmony_ci l &= ~(3 << 1); 28462306a36Sopenharmony_ci omap_writel(l, USB_TRANSCEIVER_CTRL); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (is_device) { 29062306a36Sopenharmony_ci omap_cfg_reg(W4_USB_PUEN); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (nwires == 2) { 29462306a36Sopenharmony_ci u32 l; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci // omap_cfg_reg(P9_USB_DP); 29762306a36Sopenharmony_ci // omap_cfg_reg(R8_USB_DM); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (cpu_is_omap15xx()) { 30062306a36Sopenharmony_ci /* This works on 1510-Innovator */ 30162306a36Sopenharmony_ci return 0; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* NOTES: 30562306a36Sopenharmony_ci * - peripheral should configure VBUS detection! 30662306a36Sopenharmony_ci * - only peripherals may use the internal D+/D- pulldowns 30762306a36Sopenharmony_ci * - OTG support on this port not yet written 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci l = omap_readl(USB_TRANSCEIVER_CTRL); 31162306a36Sopenharmony_ci l &= ~(7 << 4); 31262306a36Sopenharmony_ci if (!is_device) 31362306a36Sopenharmony_ci l |= (3 << 1); 31462306a36Sopenharmony_ci omap_writel(l, USB_TRANSCEIVER_CTRL); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return 3 << 16; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* alternate pin config, external transceiver */ 32062306a36Sopenharmony_ci if (cpu_is_omap15xx()) { 32162306a36Sopenharmony_ci printk(KERN_ERR "no usb0 alt pin config on 15xx\n"); 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci omap_cfg_reg(V6_USB0_TXD); 32662306a36Sopenharmony_ci omap_cfg_reg(W9_USB0_TXEN); 32762306a36Sopenharmony_ci omap_cfg_reg(W5_USB0_SE0); 32862306a36Sopenharmony_ci if (nwires != 3) 32962306a36Sopenharmony_ci omap_cfg_reg(Y5_USB0_RCV); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* NOTE: SPEED and SUSP aren't configured here. OTG hosts 33262306a36Sopenharmony_ci * may be able to use I2C requests to set those bits along 33362306a36Sopenharmony_ci * with VBUS switching and overcurrent detection. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (nwires != 6) { 33762306a36Sopenharmony_ci u32 l; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci l = omap_readl(USB_TRANSCEIVER_CTRL); 34062306a36Sopenharmony_ci l &= ~CONF_USB2_UNI_R; 34162306a36Sopenharmony_ci omap_writel(l, USB_TRANSCEIVER_CTRL); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci switch (nwires) { 34562306a36Sopenharmony_ci case 3: 34662306a36Sopenharmony_ci syscon1 = 2; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci case 4: 34962306a36Sopenharmony_ci syscon1 = 1; 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci case 6: 35262306a36Sopenharmony_ci syscon1 = 3; 35362306a36Sopenharmony_ci { 35462306a36Sopenharmony_ci u32 l; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci omap_cfg_reg(AA9_USB0_VP); 35762306a36Sopenharmony_ci omap_cfg_reg(R9_USB0_VM); 35862306a36Sopenharmony_ci l = omap_readl(USB_TRANSCEIVER_CTRL); 35962306a36Sopenharmony_ci l |= CONF_USB2_UNI_R; 36062306a36Sopenharmony_ci omap_writel(l, USB_TRANSCEIVER_CTRL); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci default: 36462306a36Sopenharmony_ci printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", 36562306a36Sopenharmony_ci 0, nwires); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return syscon1 << 16; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic u32 __init omap1_usb1_init(unsigned nwires) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci u32 syscon1 = 0; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (!cpu_is_omap15xx() && nwires != 6) { 37662306a36Sopenharmony_ci u32 l; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci l = omap_readl(USB_TRANSCEIVER_CTRL); 37962306a36Sopenharmony_ci l &= ~CONF_USB1_UNI_R; 38062306a36Sopenharmony_ci omap_writel(l, USB_TRANSCEIVER_CTRL); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci if (nwires == 0) 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* external transceiver */ 38662306a36Sopenharmony_ci omap_cfg_reg(USB1_TXD); 38762306a36Sopenharmony_ci omap_cfg_reg(USB1_TXEN); 38862306a36Sopenharmony_ci if (nwires != 3) 38962306a36Sopenharmony_ci omap_cfg_reg(USB1_RCV); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (cpu_is_omap15xx()) { 39262306a36Sopenharmony_ci omap_cfg_reg(USB1_SEO); 39362306a36Sopenharmony_ci omap_cfg_reg(USB1_SPEED); 39462306a36Sopenharmony_ci // SUSP 39562306a36Sopenharmony_ci } else if (cpu_is_omap1610() || cpu_is_omap5912()) { 39662306a36Sopenharmony_ci omap_cfg_reg(W13_1610_USB1_SE0); 39762306a36Sopenharmony_ci omap_cfg_reg(R13_1610_USB1_SPEED); 39862306a36Sopenharmony_ci // SUSP 39962306a36Sopenharmony_ci } else if (cpu_is_omap1710()) { 40062306a36Sopenharmony_ci omap_cfg_reg(R13_1710_USB1_SE0); 40162306a36Sopenharmony_ci // SUSP 40262306a36Sopenharmony_ci } else { 40362306a36Sopenharmony_ci pr_debug("usb%d cpu unrecognized\n", 1); 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci switch (nwires) { 40862306a36Sopenharmony_ci case 2: 40962306a36Sopenharmony_ci goto bad; 41062306a36Sopenharmony_ci case 3: 41162306a36Sopenharmony_ci syscon1 = 2; 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci case 4: 41462306a36Sopenharmony_ci syscon1 = 1; 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci case 6: 41762306a36Sopenharmony_ci syscon1 = 3; 41862306a36Sopenharmony_ci omap_cfg_reg(USB1_VP); 41962306a36Sopenharmony_ci omap_cfg_reg(USB1_VM); 42062306a36Sopenharmony_ci if (!cpu_is_omap15xx()) { 42162306a36Sopenharmony_ci u32 l; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci l = omap_readl(USB_TRANSCEIVER_CTRL); 42462306a36Sopenharmony_ci l |= CONF_USB1_UNI_R; 42562306a36Sopenharmony_ci omap_writel(l, USB_TRANSCEIVER_CTRL); 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci default: 42962306a36Sopenharmony_cibad: 43062306a36Sopenharmony_ci printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", 43162306a36Sopenharmony_ci 1, nwires); 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return syscon1 << 20; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic u32 __init omap1_usb2_init(unsigned nwires, unsigned alt_pingroup) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci u32 syscon1 = 0; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* NOTE omap1 erratum: must leave USB2_UNI_R set if usb0 in use */ 44262306a36Sopenharmony_ci if (alt_pingroup || nwires == 0) 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (!cpu_is_omap15xx() && nwires != 6) { 44662306a36Sopenharmony_ci u32 l; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci l = omap_readl(USB_TRANSCEIVER_CTRL); 44962306a36Sopenharmony_ci l &= ~CONF_USB2_UNI_R; 45062306a36Sopenharmony_ci omap_writel(l, USB_TRANSCEIVER_CTRL); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* external transceiver */ 45462306a36Sopenharmony_ci if (cpu_is_omap15xx()) { 45562306a36Sopenharmony_ci omap_cfg_reg(USB2_TXD); 45662306a36Sopenharmony_ci omap_cfg_reg(USB2_TXEN); 45762306a36Sopenharmony_ci omap_cfg_reg(USB2_SEO); 45862306a36Sopenharmony_ci if (nwires != 3) 45962306a36Sopenharmony_ci omap_cfg_reg(USB2_RCV); 46062306a36Sopenharmony_ci /* there is no USB2_SPEED */ 46162306a36Sopenharmony_ci } else if (cpu_is_omap16xx()) { 46262306a36Sopenharmony_ci omap_cfg_reg(V6_USB2_TXD); 46362306a36Sopenharmony_ci omap_cfg_reg(W9_USB2_TXEN); 46462306a36Sopenharmony_ci omap_cfg_reg(W5_USB2_SE0); 46562306a36Sopenharmony_ci if (nwires != 3) 46662306a36Sopenharmony_ci omap_cfg_reg(Y5_USB2_RCV); 46762306a36Sopenharmony_ci // FIXME omap_cfg_reg(USB2_SPEED); 46862306a36Sopenharmony_ci } else { 46962306a36Sopenharmony_ci pr_debug("usb%d cpu unrecognized\n", 1); 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci // omap_cfg_reg(USB2_SUSP); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci switch (nwires) { 47662306a36Sopenharmony_ci case 2: 47762306a36Sopenharmony_ci goto bad; 47862306a36Sopenharmony_ci case 3: 47962306a36Sopenharmony_ci syscon1 = 2; 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci case 4: 48262306a36Sopenharmony_ci syscon1 = 1; 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci case 5: 48562306a36Sopenharmony_ci goto bad; 48662306a36Sopenharmony_ci case 6: 48762306a36Sopenharmony_ci syscon1 = 3; 48862306a36Sopenharmony_ci if (cpu_is_omap15xx()) { 48962306a36Sopenharmony_ci omap_cfg_reg(USB2_VP); 49062306a36Sopenharmony_ci omap_cfg_reg(USB2_VM); 49162306a36Sopenharmony_ci } else { 49262306a36Sopenharmony_ci u32 l; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci omap_cfg_reg(AA9_USB2_VP); 49562306a36Sopenharmony_ci omap_cfg_reg(R9_USB2_VM); 49662306a36Sopenharmony_ci l = omap_readl(USB_TRANSCEIVER_CTRL); 49762306a36Sopenharmony_ci l |= CONF_USB2_UNI_R; 49862306a36Sopenharmony_ci omap_writel(l, USB_TRANSCEIVER_CTRL); 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci default: 50262306a36Sopenharmony_cibad: 50362306a36Sopenharmony_ci printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", 50462306a36Sopenharmony_ci 2, nwires); 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return syscon1 << 24; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci#ifdef CONFIG_ARCH_OMAP15XX 51162306a36Sopenharmony_ci/* OMAP-1510 OHCI has its own MMU for DMA */ 51262306a36Sopenharmony_ci#define OMAP1510_LB_MEMSIZE 32 /* Should be same as SDRAM size */ 51362306a36Sopenharmony_ci#define OMAP1510_LB_CLOCK_DIV 0xfffec10c 51462306a36Sopenharmony_ci#define OMAP1510_LB_MMU_CTL 0xfffec208 51562306a36Sopenharmony_ci#define OMAP1510_LB_MMU_LCK 0xfffec224 51662306a36Sopenharmony_ci#define OMAP1510_LB_MMU_LD_TLB 0xfffec228 51762306a36Sopenharmony_ci#define OMAP1510_LB_MMU_CAM_H 0xfffec22c 51862306a36Sopenharmony_ci#define OMAP1510_LB_MMU_CAM_L 0xfffec230 51962306a36Sopenharmony_ci#define OMAP1510_LB_MMU_RAM_H 0xfffec234 52062306a36Sopenharmony_ci#define OMAP1510_LB_MMU_RAM_L 0xfffec238 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/* 52362306a36Sopenharmony_ci * Bus address is physical address, except for OMAP-1510 Local Bus. 52462306a36Sopenharmony_ci * OMAP-1510 bus address is translated into a Local Bus address if the 52562306a36Sopenharmony_ci * OMAP bus type is lbus. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_ci#define OMAP1510_LB_OFFSET UL(0x30000000) 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci/* 53062306a36Sopenharmony_ci * OMAP-1510 specific Local Bus clock on/off 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_cistatic int omap_1510_local_bus_power(int on) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci if (on) { 53562306a36Sopenharmony_ci omap_writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL); 53662306a36Sopenharmony_ci udelay(200); 53762306a36Sopenharmony_ci } else { 53862306a36Sopenharmony_ci omap_writel(0, OMAP1510_LB_MMU_CTL); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return 0; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci/* 54562306a36Sopenharmony_ci * OMAP-1510 specific Local Bus initialization 54662306a36Sopenharmony_ci * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE. 54762306a36Sopenharmony_ci * See also arch/mach-omap/memory.h for __virt_to_dma() and 54862306a36Sopenharmony_ci * __dma_to_virt() which need to match with the physical 54962306a36Sopenharmony_ci * Local Bus address below. 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_cistatic int omap_1510_local_bus_init(void) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci unsigned int tlb; 55462306a36Sopenharmony_ci unsigned long lbaddr, physaddr; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, 55762306a36Sopenharmony_ci OMAP1510_LB_CLOCK_DIV); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* Configure the Local Bus MMU table */ 56062306a36Sopenharmony_ci for (tlb = 0; tlb < OMAP1510_LB_MEMSIZE; tlb++) { 56162306a36Sopenharmony_ci lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET; 56262306a36Sopenharmony_ci physaddr = tlb * 0x00100000 + PHYS_OFFSET; 56362306a36Sopenharmony_ci omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); 56462306a36Sopenharmony_ci omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, 56562306a36Sopenharmony_ci OMAP1510_LB_MMU_CAM_L); 56662306a36Sopenharmony_ci omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); 56762306a36Sopenharmony_ci omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); 56862306a36Sopenharmony_ci omap_writel(tlb << 4, OMAP1510_LB_MMU_LCK); 56962306a36Sopenharmony_ci omap_writel(0x1, OMAP1510_LB_MMU_LD_TLB); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Enable the walking table */ 57362306a36Sopenharmony_ci omap_writel(omap_readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL); 57462306a36Sopenharmony_ci udelay(200); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic void omap_1510_local_bus_reset(void) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci omap_1510_local_bus_power(1); 58262306a36Sopenharmony_ci omap_1510_local_bus_init(); 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci/* ULPD_DPLL_CTRL */ 58662306a36Sopenharmony_ci#define DPLL_IOB (1 << 13) 58762306a36Sopenharmony_ci#define DPLL_PLL_ENABLE (1 << 4) 58862306a36Sopenharmony_ci#define DPLL_LOCK (1 << 0) 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci/* ULPD_APLL_CTRL */ 59162306a36Sopenharmony_ci#define APLL_NDPLL_SWITCH (1 << 0) 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic void __init omap_1510_usb_init(struct omap_usb_config *config) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci unsigned int val; 59662306a36Sopenharmony_ci u16 w; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci config->usb0_init(config->pins[0], is_usb0_device(config)); 59962306a36Sopenharmony_ci config->usb1_init(config->pins[1]); 60062306a36Sopenharmony_ci config->usb2_init(config->pins[2], 0); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1); 60362306a36Sopenharmony_ci val |= (config->hmc_mode << 1); 60462306a36Sopenharmony_ci omap_writel(val, MOD_CONF_CTRL_0); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci printk("USB: hmc %d", config->hmc_mode); 60762306a36Sopenharmony_ci if (config->pins[0]) 60862306a36Sopenharmony_ci pr_cont(", usb0 %d wires%s", config->pins[0], 60962306a36Sopenharmony_ci is_usb0_device(config) ? " (dev)" : ""); 61062306a36Sopenharmony_ci if (config->pins[1]) 61162306a36Sopenharmony_ci pr_cont(", usb1 %d wires", config->pins[1]); 61262306a36Sopenharmony_ci if (config->pins[2]) 61362306a36Sopenharmony_ci pr_cont(", usb2 %d wires", config->pins[2]); 61462306a36Sopenharmony_ci pr_cont("\n"); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* use DPLL for 48 MHz function clock */ 61762306a36Sopenharmony_ci pr_debug("APLL %04x DPLL %04x REQ %04x\n", omap_readw(ULPD_APLL_CTRL), 61862306a36Sopenharmony_ci omap_readw(ULPD_DPLL_CTRL), omap_readw(ULPD_SOFT_REQ)); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci w = omap_readw(ULPD_APLL_CTRL); 62162306a36Sopenharmony_ci w &= ~APLL_NDPLL_SWITCH; 62262306a36Sopenharmony_ci omap_writew(w, ULPD_APLL_CTRL); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci w = omap_readw(ULPD_DPLL_CTRL); 62562306a36Sopenharmony_ci w |= DPLL_IOB | DPLL_PLL_ENABLE; 62662306a36Sopenharmony_ci omap_writew(w, ULPD_DPLL_CTRL); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci w = omap_readw(ULPD_SOFT_REQ); 62962306a36Sopenharmony_ci w |= SOFT_UDC_REQ | SOFT_DPLL_REQ; 63062306a36Sopenharmony_ci omap_writew(w, ULPD_SOFT_REQ); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci while (!(omap_readw(ULPD_DPLL_CTRL) & DPLL_LOCK)) 63362306a36Sopenharmony_ci cpu_relax(); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_OMAP) 63662306a36Sopenharmony_ci if (config->register_dev) { 63762306a36Sopenharmony_ci int status; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci udc_device.dev.platform_data = config; 64062306a36Sopenharmony_ci status = platform_device_register(&udc_device); 64162306a36Sopenharmony_ci if (status) 64262306a36Sopenharmony_ci pr_debug("can't register UDC device, %d\n", status); 64362306a36Sopenharmony_ci /* udc driver gates 48MHz by D+ pullup */ 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci#endif 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_USB_OHCI_HCD) && config->register_host) { 64862306a36Sopenharmony_ci int status; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci ohci_device.dev.platform_data = config; 65162306a36Sopenharmony_ci dma_direct_set_offset(&ohci_device.dev, PHYS_OFFSET, 65262306a36Sopenharmony_ci OMAP1510_LB_OFFSET, (u64)-1); 65362306a36Sopenharmony_ci status = platform_device_register(&ohci_device); 65462306a36Sopenharmony_ci if (status) 65562306a36Sopenharmony_ci pr_debug("can't register OHCI device, %d\n", status); 65662306a36Sopenharmony_ci /* hcd explicitly gates 48MHz */ 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci config->lb_reset = omap_1510_local_bus_reset; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci#else 66362306a36Sopenharmony_cistatic inline void omap_1510_usb_init(struct omap_usb_config *config) {} 66462306a36Sopenharmony_ci#endif 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_civoid __init omap1_usb_init(struct omap_usb_config *_pdata) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci struct omap_usb_config *pdata; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci pdata = kmemdup(_pdata, sizeof(*pdata), GFP_KERNEL); 67162306a36Sopenharmony_ci if (!pdata) 67262306a36Sopenharmony_ci return; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci pdata->usb0_init = omap1_usb0_init; 67562306a36Sopenharmony_ci pdata->usb1_init = omap1_usb1_init; 67662306a36Sopenharmony_ci pdata->usb2_init = omap1_usb2_init; 67762306a36Sopenharmony_ci udc_device_init(pdata); 67862306a36Sopenharmony_ci ohci_device_init(pdata); 67962306a36Sopenharmony_ci otg_device_init(pdata); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (cpu_is_omap16xx()) 68262306a36Sopenharmony_ci omap_otg_init(pdata); 68362306a36Sopenharmony_ci else if (cpu_is_omap15xx()) 68462306a36Sopenharmony_ci omap_1510_usb_init(pdata); 68562306a36Sopenharmony_ci else 68662306a36Sopenharmony_ci printk(KERN_ERR "USB: No init for your chip yet\n"); 68762306a36Sopenharmony_ci} 688