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