1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * am35x.c - TI's AM35x platform specific usb wrapper functions.
4  *
5  * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
6  *
7  * Based on drivers/usb/musb/da8xx.c
8  *
9  * Copyright (c) 2010 Texas Instruments Incorporated
10  */
11 
12 #include <common.h>
13 #include <linux/delay.h>
14 
15 #include "am35x.h"
16 
17 /* MUSB platform configuration */
18 struct musb_config musb_cfg = {
19 	.regs		= (struct musb_regs *)AM35X_USB_OTG_CORE_BASE,
20 	.timeout	= AM35X_USB_OTG_TIMEOUT,
21 	.musb_speed	= 0,
22 };
23 
24 /*
25  * Enable the USB phy
26  */
phy_on(void)27 static u8 phy_on(void)
28 {
29 	u32 devconf2;
30 	u32 timeout;
31 
32 	devconf2 = readl(&am35x_scm_general_regs->devconf2);
33 
34 	devconf2 &= ~(DEVCONF2_RESET | DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN |
35 		      DEVCONF2_OTGMODE | DEVCONF2_REFFREQ |
36 		      DEVCONF2_PHY_GPIOMODE);
37 	devconf2 |= DEVCONF2_SESENDEN | DEVCONF2_VBDTCTEN | DEVCONF2_PHY_PLLON |
38 		    DEVCONF2_REFFREQ_13MHZ | DEVCONF2_DATPOL;
39 
40 	writel(devconf2, &am35x_scm_general_regs->devconf2);
41 
42 	/* wait until the USB phy is turned on */
43 	timeout = musb_cfg.timeout;
44 	while (timeout--)
45 		if (readl(&am35x_scm_general_regs->devconf2) & DEVCONF2_PHYCKGD)
46 			return 1;
47 
48 	/* USB phy was not turned on */
49 	return 0;
50 }
51 
52 /*
53  * Disable the USB phy
54  */
phy_off(void)55 static void phy_off(void)
56 {
57 	u32 devconf2;
58 
59 	/*
60 	 * Power down the on-chip PHY.
61 	 */
62 	devconf2 = readl(&am35x_scm_general_regs->devconf2);
63 
64 	devconf2 &= ~DEVCONF2_PHY_PLLON;
65 	devconf2 |= DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN;
66 	writel(devconf2, &am35x_scm_general_regs->devconf2);
67 }
68 
69 /*
70  * This function performs platform specific initialization for usb0.
71  */
musb_platform_init(void)72 int musb_platform_init(void)
73 {
74 	u32 revision;
75 	u32 sw_reset;
76 
77 	/* global usb reset */
78 	sw_reset = readl(&am35x_scm_general_regs->ip_sw_reset);
79 	sw_reset |= (1 << 0);
80 	writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset);
81 	sw_reset &= ~(1 << 0);
82 	writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset);
83 
84 	/* reset the controller */
85 	writel(0x1, &am35x_usb_regs->control);
86 	udelay(5000);
87 
88 	/* start the on-chip usb phy and its pll */
89 	if (phy_on() == 0)
90 		return -1;
91 
92 	/* Returns zero if e.g. not clocked */
93 	revision = readl(&am35x_usb_regs->revision);
94 	if (revision == 0)
95 		return -1;
96 
97 	return 0;
98 }
99 
100 /*
101  * This function performs platform specific deinitialization for usb0.
102  */
musb_platform_deinit(void)103 void musb_platform_deinit(void)
104 {
105 	/* Turn off the phy */
106 	phy_off();
107 }
108 
109 /*
110  * This function reads data from endpoint fifo for AM35x
111  * which supports only 32bit read operation.
112  *
113  * ep           - endpoint number
114  * length       - number of bytes to read from FIFO
115  * fifo_data    - pointer to data buffer into which data is read
116  */
117 __attribute__((weak))
read_fifo(u8 ep,u32 length,void * fifo_data)118 void read_fifo(u8 ep, u32 length, void *fifo_data)
119 {
120 	u8  *data = (u8 *)fifo_data;
121 	u32 val;
122 	int i;
123 
124 	/* select the endpoint index */
125 	writeb(ep, &musbr->index);
126 
127 	if (length > 4) {
128 		for (i = 0; i < (length >> 2); i++) {
129 			val = readl(&musbr->fifox[ep]);
130 			memcpy(data, &val, 4);
131 			data += 4;
132 		}
133 		length %= 4;
134 	}
135 	if (length > 0) {
136 		val = readl(&musbr->fifox[ep]);
137 		memcpy(data, &val, length);
138 	}
139 }
140