xref: /openbmc/u-boot/drivers/usb/ulpi/ulpi.c (revision e8f80a5a)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
4  * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
5  *
6  * Authors: Jana Rapava <fermata7@gmail.com>
7  *	    Igor Grinberg <grinberg@compulab.co.il>
8  *
9  * Based on:
10  * linux/drivers/usb/otg/ulpi.c
11  * Generic ULPI USB transceiver support
12  *
13  * Original Copyright follow:
14  * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
15  *
16  * Based on sources from
17  *
18  *   Sascha Hauer <s.hauer@pengutronix.de>
19  *   Freescale Semiconductors
20  */
21 
22 #include <common.h>
23 #include <exports.h>
24 #include <usb/ulpi.h>
25 
26 #define ULPI_ID_REGS_COUNT	4
27 #define ULPI_TEST_VALUE		0x55	/* 0x55 == 0b01010101 */
28 
29 static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
30 
ulpi_integrity_check(struct ulpi_viewport * ulpi_vp)31 static int ulpi_integrity_check(struct ulpi_viewport *ulpi_vp)
32 {
33 	u32 val, tval = ULPI_TEST_VALUE;
34 	int err, i;
35 
36 	/* Use the 'special' test value to check all bits */
37 	for (i = 0; i < 2; i++, tval <<= 1) {
38 		err = ulpi_write(ulpi_vp, &ulpi->scratch, tval);
39 		if (err)
40 			return err;
41 
42 		val = ulpi_read(ulpi_vp, &ulpi->scratch);
43 		if (val != tval) {
44 			printf("ULPI integrity check failed\n");
45 			return val;
46 		}
47 	}
48 
49 	return 0;
50 }
51 
ulpi_init(struct ulpi_viewport * ulpi_vp)52 int ulpi_init(struct ulpi_viewport *ulpi_vp)
53 {
54 	u32 val, id = 0;
55 	u8 *reg = &ulpi->product_id_high;
56 	int i;
57 
58 	/* Assemble ID from four ULPI ID registers (8 bits each). */
59 	for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
60 		val = ulpi_read(ulpi_vp, reg - i);
61 		if (val == ULPI_ERROR)
62 			return val;
63 
64 		id = (id << 8) | val;
65 	}
66 
67 	/* Split ID into vendor and product ID. */
68 	debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
69 
70 	return ulpi_integrity_check(ulpi_vp);
71 }
72 
ulpi_select_transceiver(struct ulpi_viewport * ulpi_vp,unsigned speed)73 int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)
74 {
75 	u32 tspeed = ULPI_FC_FULL_SPEED;
76 	u32 val;
77 
78 	switch (speed) {
79 	case ULPI_FC_HIGH_SPEED:
80 	case ULPI_FC_FULL_SPEED:
81 	case ULPI_FC_LOW_SPEED:
82 	case ULPI_FC_FS4LS:
83 		tspeed = speed;
84 		break;
85 	default:
86 		printf("ULPI: %s: wrong transceiver speed specified: %u, "
87 			"falling back to full speed\n", __func__, speed);
88 	}
89 
90 	val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
91 	if (val == ULPI_ERROR)
92 		return val;
93 
94 	/* clear the previous speed setting */
95 	val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
96 
97 	return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
98 }
99 
ulpi_set_vbus(struct ulpi_viewport * ulpi_vp,int on,int ext_power)100 int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power)
101 {
102 	u32 flags = ULPI_OTG_DRVVBUS;
103 	u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
104 
105 	if (ext_power)
106 		flags |= ULPI_OTG_DRVVBUS_EXT;
107 
108 	return ulpi_write(ulpi_vp, reg, flags);
109 }
110 
ulpi_set_vbus_indicator(struct ulpi_viewport * ulpi_vp,int external,int passthu,int complement)111 int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external,
112 			int passthu, int complement)
113 {
114 	u32 flags, val;
115 	u8 *reg;
116 
117 	reg = external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
118 	val = ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);
119 	if (val)
120 		return val;
121 
122 	flags = passthu ? ULPI_IFACE_PASSTHRU : 0;
123 	flags |= complement ? ULPI_IFACE_EXTVBUS_COMPLEMENT : 0;
124 
125 	val = ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
126 	if (val == ULPI_ERROR)
127 		return val;
128 
129 	val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT);
130 	val |= flags;
131 	val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
132 	if (val)
133 		return val;
134 
135 	return 0;
136 }
137 
ulpi_set_pd(struct ulpi_viewport * ulpi_vp,int enable)138 int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable)
139 {
140 	u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
141 	u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
142 
143 	return ulpi_write(ulpi_vp, reg, val);
144 }
145 
ulpi_opmode_sel(struct ulpi_viewport * ulpi_vp,unsigned opmode)146 int ulpi_opmode_sel(struct ulpi_viewport *ulpi_vp, unsigned opmode)
147 {
148 	u32 topmode = ULPI_FC_OPMODE_NORMAL;
149 	u32 val;
150 
151 	switch (opmode) {
152 	case ULPI_FC_OPMODE_NORMAL:
153 	case ULPI_FC_OPMODE_NONDRIVING:
154 	case ULPI_FC_OPMODE_DISABLE_NRZI:
155 	case ULPI_FC_OPMODE_NOSYNC_NOEOP:
156 		topmode = opmode;
157 		break;
158 	default:
159 		printf("ULPI: %s: wrong OpMode specified: %u, "
160 			"falling back to OpMode Normal\n", __func__, opmode);
161 	}
162 
163 	val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
164 	if (val == ULPI_ERROR)
165 		return val;
166 
167 	/* clear the previous opmode setting */
168 	val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
169 
170 	return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
171 }
172 
ulpi_serial_mode_enable(struct ulpi_viewport * ulpi_vp,unsigned smode)173 int ulpi_serial_mode_enable(struct ulpi_viewport *ulpi_vp, unsigned smode)
174 {
175 	switch (smode) {
176 	case ULPI_IFACE_6_PIN_SERIAL_MODE:
177 	case ULPI_IFACE_3_PIN_SERIAL_MODE:
178 		break;
179 	default:
180 		printf("ULPI: %s: unrecognized Serial Mode specified: %u\n",
181 			__func__, smode);
182 		return ULPI_ERROR;
183 	}
184 
185 	return ulpi_write(ulpi_vp, &ulpi->iface_ctrl_set, smode);
186 }
187 
ulpi_suspend(struct ulpi_viewport * ulpi_vp)188 int ulpi_suspend(struct ulpi_viewport *ulpi_vp)
189 {
190 	int err;
191 
192 	err = ulpi_write(ulpi_vp, &ulpi->function_ctrl_clear,
193 			ULPI_FC_SUSPENDM);
194 	if (err)
195 		printf("ULPI: %s: failed writing the suspend bit\n", __func__);
196 
197 	return err;
198 }
199 
200 /*
201  * Wait for ULPI PHY reset to complete.
202  * Actual wait for reset must be done in a view port specific way,
203  * because it involves checking the DIR line.
204  */
__ulpi_reset_wait(struct ulpi_viewport * ulpi_vp)205 static int __ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
206 {
207 	u32 val;
208 	int timeout = CONFIG_USB_ULPI_TIMEOUT;
209 
210 	/* Wait for the RESET bit to become zero */
211 	while (--timeout) {
212 		/*
213 		 * This function is generic and suppose to work
214 		 * with any viewport, so we cheat here and don't check
215 		 * for the error of ulpi_read(), if there is one, then
216 		 * there will be a timeout.
217 		 */
218 		val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
219 		if (!(val & ULPI_FC_RESET))
220 			return 0;
221 
222 		udelay(1);
223 	}
224 
225 	printf("ULPI: %s: reset timed out\n", __func__);
226 
227 	return ULPI_ERROR;
228 }
229 int ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
230 	__attribute__((weak, alias("__ulpi_reset_wait")));
231 
ulpi_reset(struct ulpi_viewport * ulpi_vp)232 int ulpi_reset(struct ulpi_viewport *ulpi_vp)
233 {
234 	int err;
235 
236 	err = ulpi_write(ulpi_vp,
237 			&ulpi->function_ctrl_set, ULPI_FC_RESET);
238 	if (err) {
239 		printf("ULPI: %s: failed writing reset bit\n", __func__);
240 		return err;
241 	}
242 
243 	return ulpi_reset_wait(ulpi_vp);
244 }
245