xref: /rk3399_rockchip-uboot/drivers/usb/ulpi/ulpi.c (revision 326ea986ac150acdc7656d57fca647db80b50158)
1f93022c3SJana Rapava /*
2f93022c3SJana Rapava  * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
3f93022c3SJana Rapava  * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
4f93022c3SJana Rapava  *
5f93022c3SJana Rapava  * Authors: Jana Rapava <fermata7@gmail.com>
6f93022c3SJana Rapava  *	    Igor Grinberg <grinberg@compulab.co.il>
7f93022c3SJana Rapava  *
8f93022c3SJana Rapava  * Based on:
9f93022c3SJana Rapava  * linux/drivers/usb/otg/ulpi.c
10f93022c3SJana Rapava  * Generic ULPI USB transceiver support
11f93022c3SJana Rapava  *
12f93022c3SJana Rapava  * Original Copyright follow:
13f93022c3SJana Rapava  * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
14f93022c3SJana Rapava  *
15f93022c3SJana Rapava  * Based on sources from
16f93022c3SJana Rapava  *
17f93022c3SJana Rapava  *   Sascha Hauer <s.hauer@pengutronix.de>
18f93022c3SJana Rapava  *   Freescale Semiconductors
19f93022c3SJana Rapava  *
20*1a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
21f93022c3SJana Rapava  */
22f93022c3SJana Rapava 
23f93022c3SJana Rapava #include <common.h>
24f93022c3SJana Rapava #include <exports.h>
25f93022c3SJana Rapava #include <usb/ulpi.h>
26f93022c3SJana Rapava 
27f93022c3SJana Rapava #define ULPI_ID_REGS_COUNT	4
28f93022c3SJana Rapava #define ULPI_TEST_VALUE		0x55	/* 0x55 == 0b01010101 */
29f93022c3SJana Rapava 
30f93022c3SJana Rapava static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
31f93022c3SJana Rapava 
ulpi_integrity_check(struct ulpi_viewport * ulpi_vp)323e6e809fSGovindraj.R static int ulpi_integrity_check(struct ulpi_viewport *ulpi_vp)
33f93022c3SJana Rapava {
344256101fSIgor Grinberg 	u32 val, tval = ULPI_TEST_VALUE;
354256101fSIgor Grinberg 	int err, i;
36f93022c3SJana Rapava 
37f93022c3SJana Rapava 	/* Use the 'special' test value to check all bits */
38f93022c3SJana Rapava 	for (i = 0; i < 2; i++, tval <<= 1) {
393e6e809fSGovindraj.R 		err = ulpi_write(ulpi_vp, &ulpi->scratch, tval);
40f93022c3SJana Rapava 		if (err)
41f93022c3SJana Rapava 			return err;
42f93022c3SJana Rapava 
433e6e809fSGovindraj.R 		val = ulpi_read(ulpi_vp, &ulpi->scratch);
44f93022c3SJana Rapava 		if (val != tval) {
45f93022c3SJana Rapava 			printf("ULPI integrity check failed\n");
46f93022c3SJana Rapava 			return val;
47f93022c3SJana Rapava 		}
48f93022c3SJana Rapava 	}
49f93022c3SJana Rapava 
50f93022c3SJana Rapava 	return 0;
51f93022c3SJana Rapava }
52f93022c3SJana Rapava 
ulpi_init(struct ulpi_viewport * ulpi_vp)533e6e809fSGovindraj.R int ulpi_init(struct ulpi_viewport *ulpi_vp)
54f93022c3SJana Rapava {
55f93022c3SJana Rapava 	u32 val, id = 0;
56f93022c3SJana Rapava 	u8 *reg = &ulpi->product_id_high;
57f93022c3SJana Rapava 	int i;
58f93022c3SJana Rapava 
59f93022c3SJana Rapava 	/* Assemble ID from four ULPI ID registers (8 bits each). */
60f93022c3SJana Rapava 	for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
613e6e809fSGovindraj.R 		val = ulpi_read(ulpi_vp, reg - i);
62f93022c3SJana Rapava 		if (val == ULPI_ERROR)
63f93022c3SJana Rapava 			return val;
64f93022c3SJana Rapava 
65f93022c3SJana Rapava 		id = (id << 8) | val;
66f93022c3SJana Rapava 	}
67f93022c3SJana Rapava 
68f93022c3SJana Rapava 	/* Split ID into vendor and product ID. */
69f93022c3SJana Rapava 	debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
70f93022c3SJana Rapava 
713e6e809fSGovindraj.R 	return ulpi_integrity_check(ulpi_vp);
72f93022c3SJana Rapava }
73f93022c3SJana Rapava 
ulpi_select_transceiver(struct ulpi_viewport * ulpi_vp,unsigned speed)743e6e809fSGovindraj.R int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)
75f93022c3SJana Rapava {
761113a79bSIgor Grinberg 	u32 tspeed = ULPI_FC_FULL_SPEED;
77f93022c3SJana Rapava 	u32 val;
78f93022c3SJana Rapava 
79f93022c3SJana Rapava 	switch (speed) {
80f93022c3SJana Rapava 	case ULPI_FC_HIGH_SPEED:
81f93022c3SJana Rapava 	case ULPI_FC_FULL_SPEED:
82f93022c3SJana Rapava 	case ULPI_FC_LOW_SPEED:
83f93022c3SJana Rapava 	case ULPI_FC_FS4LS:
84f93022c3SJana Rapava 		tspeed = speed;
85f93022c3SJana Rapava 		break;
86f93022c3SJana Rapava 	default:
87cf9f95f2SIgor Grinberg 		printf("ULPI: %s: wrong transceiver speed specified: %u, "
88cf9f95f2SIgor Grinberg 			"falling back to full speed\n", __func__, speed);
89f93022c3SJana Rapava 	}
90f93022c3SJana Rapava 
913e6e809fSGovindraj.R 	val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
92f93022c3SJana Rapava 	if (val == ULPI_ERROR)
93f93022c3SJana Rapava 		return val;
94f93022c3SJana Rapava 
95f93022c3SJana Rapava 	/* clear the previous speed setting */
96f93022c3SJana Rapava 	val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
97f93022c3SJana Rapava 
983e6e809fSGovindraj.R 	return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
99f93022c3SJana Rapava }
100f93022c3SJana Rapava 
ulpi_set_vbus(struct ulpi_viewport * ulpi_vp,int on,int ext_power)101141288b3SLucas Stach int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power)
102f93022c3SJana Rapava {
103f93022c3SJana Rapava 	u32 flags = ULPI_OTG_DRVVBUS;
104f93022c3SJana Rapava 	u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
105f93022c3SJana Rapava 
106f93022c3SJana Rapava 	if (ext_power)
107f93022c3SJana Rapava 		flags |= ULPI_OTG_DRVVBUS_EXT;
108f93022c3SJana Rapava 
1093e6e809fSGovindraj.R 	return ulpi_write(ulpi_vp, reg, flags);
110f93022c3SJana Rapava }
111f93022c3SJana Rapava 
ulpi_set_vbus_indicator(struct ulpi_viewport * ulpi_vp,int external,int passthu,int complement)112141288b3SLucas Stach int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external,
113141288b3SLucas Stach 			int passthu, int complement)
114141288b3SLucas Stach {
115141288b3SLucas Stach 	u32 flags, val;
116141288b3SLucas Stach 	u8 *reg;
117141288b3SLucas Stach 
118141288b3SLucas Stach 	reg = external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
119141288b3SLucas Stach 	val = ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);
120141288b3SLucas Stach 	if (val)
121141288b3SLucas Stach 		return val;
122141288b3SLucas Stach 
123141288b3SLucas Stach 	flags = passthu ? ULPI_IFACE_PASSTHRU : 0;
124141288b3SLucas Stach 	flags |= complement ? ULPI_IFACE_EXTVBUS_COMPLEMENT : 0;
125141288b3SLucas Stach 
126141288b3SLucas Stach 	val = ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
127141288b3SLucas Stach 	if (val == ULPI_ERROR)
128141288b3SLucas Stach 		return val;
129141288b3SLucas Stach 
130141288b3SLucas Stach 	val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT);
131141288b3SLucas Stach 	val |= flags;
132141288b3SLucas Stach 	val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
133141288b3SLucas Stach 	if (val)
134141288b3SLucas Stach 		return val;
135141288b3SLucas Stach 
136141288b3SLucas Stach 	return 0;
137141288b3SLucas Stach }
138141288b3SLucas Stach 
ulpi_set_pd(struct ulpi_viewport * ulpi_vp,int enable)1393e6e809fSGovindraj.R int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable)
140f93022c3SJana Rapava {
141f93022c3SJana Rapava 	u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
142f93022c3SJana Rapava 	u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
143f93022c3SJana Rapava 
1443e6e809fSGovindraj.R 	return ulpi_write(ulpi_vp, reg, val);
145f93022c3SJana Rapava }
146f93022c3SJana Rapava 
ulpi_opmode_sel(struct ulpi_viewport * ulpi_vp,unsigned opmode)1473e6e809fSGovindraj.R int ulpi_opmode_sel(struct ulpi_viewport *ulpi_vp, unsigned opmode)
148f93022c3SJana Rapava {
1491113a79bSIgor Grinberg 	u32 topmode = ULPI_FC_OPMODE_NORMAL;
150f93022c3SJana Rapava 	u32 val;
151f93022c3SJana Rapava 
152f93022c3SJana Rapava 	switch (opmode) {
153f93022c3SJana Rapava 	case ULPI_FC_OPMODE_NORMAL:
154f93022c3SJana Rapava 	case ULPI_FC_OPMODE_NONDRIVING:
155f93022c3SJana Rapava 	case ULPI_FC_OPMODE_DISABLE_NRZI:
156f93022c3SJana Rapava 	case ULPI_FC_OPMODE_NOSYNC_NOEOP:
157f93022c3SJana Rapava 		topmode = opmode;
158f93022c3SJana Rapava 		break;
159f93022c3SJana Rapava 	default:
160cf9f95f2SIgor Grinberg 		printf("ULPI: %s: wrong OpMode specified: %u, "
161cf9f95f2SIgor Grinberg 			"falling back to OpMode Normal\n", __func__, opmode);
162f93022c3SJana Rapava 	}
163f93022c3SJana Rapava 
1643e6e809fSGovindraj.R 	val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
165f93022c3SJana Rapava 	if (val == ULPI_ERROR)
166f93022c3SJana Rapava 		return val;
167f93022c3SJana Rapava 
168f93022c3SJana Rapava 	/* clear the previous opmode setting */
169f93022c3SJana Rapava 	val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
170f93022c3SJana Rapava 
1713e6e809fSGovindraj.R 	return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
172f93022c3SJana Rapava }
173f93022c3SJana Rapava 
ulpi_serial_mode_enable(struct ulpi_viewport * ulpi_vp,unsigned smode)1743e6e809fSGovindraj.R int ulpi_serial_mode_enable(struct ulpi_viewport *ulpi_vp, unsigned smode)
175f93022c3SJana Rapava {
176f93022c3SJana Rapava 	switch (smode) {
177f93022c3SJana Rapava 	case ULPI_IFACE_6_PIN_SERIAL_MODE:
178f93022c3SJana Rapava 	case ULPI_IFACE_3_PIN_SERIAL_MODE:
179f93022c3SJana Rapava 		break;
180f93022c3SJana Rapava 	default:
181cf9f95f2SIgor Grinberg 		printf("ULPI: %s: unrecognized Serial Mode specified: %u\n",
182cf9f95f2SIgor Grinberg 			__func__, smode);
183f93022c3SJana Rapava 		return ULPI_ERROR;
184f93022c3SJana Rapava 	}
185f93022c3SJana Rapava 
1863e6e809fSGovindraj.R 	return ulpi_write(ulpi_vp, &ulpi->iface_ctrl_set, smode);
187f93022c3SJana Rapava }
188f93022c3SJana Rapava 
ulpi_suspend(struct ulpi_viewport * ulpi_vp)1893e6e809fSGovindraj.R int ulpi_suspend(struct ulpi_viewport *ulpi_vp)
190f93022c3SJana Rapava {
1914256101fSIgor Grinberg 	int err;
192f93022c3SJana Rapava 
1933e6e809fSGovindraj.R 	err = ulpi_write(ulpi_vp, &ulpi->function_ctrl_clear,
194f93022c3SJana Rapava 			ULPI_FC_SUSPENDM);
195f93022c3SJana Rapava 	if (err)
196f93022c3SJana Rapava 		printf("ULPI: %s: failed writing the suspend bit\n", __func__);
197f93022c3SJana Rapava 
198f93022c3SJana Rapava 	return err;
199f93022c3SJana Rapava }
200f93022c3SJana Rapava 
201f93022c3SJana Rapava /*
202f93022c3SJana Rapava  * Wait for ULPI PHY reset to complete.
203f93022c3SJana Rapava  * Actual wait for reset must be done in a view port specific way,
204f93022c3SJana Rapava  * because it involves checking the DIR line.
205f93022c3SJana Rapava  */
__ulpi_reset_wait(struct ulpi_viewport * ulpi_vp)2063e6e809fSGovindraj.R static int __ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
207f93022c3SJana Rapava {
208f93022c3SJana Rapava 	u32 val;
209f93022c3SJana Rapava 	int timeout = CONFIG_USB_ULPI_TIMEOUT;
210f93022c3SJana Rapava 
211f93022c3SJana Rapava 	/* Wait for the RESET bit to become zero */
212f93022c3SJana Rapava 	while (--timeout) {
213f93022c3SJana Rapava 		/*
214f93022c3SJana Rapava 		 * This function is generic and suppose to work
215f93022c3SJana Rapava 		 * with any viewport, so we cheat here and don't check
216f93022c3SJana Rapava 		 * for the error of ulpi_read(), if there is one, then
217f93022c3SJana Rapava 		 * there will be a timeout.
218f93022c3SJana Rapava 		 */
2193e6e809fSGovindraj.R 		val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
220f93022c3SJana Rapava 		if (!(val & ULPI_FC_RESET))
221f93022c3SJana Rapava 			return 0;
222f93022c3SJana Rapava 
223f93022c3SJana Rapava 		udelay(1);
224f93022c3SJana Rapava 	}
225f93022c3SJana Rapava 
226f93022c3SJana Rapava 	printf("ULPI: %s: reset timed out\n", __func__);
227f93022c3SJana Rapava 
228f93022c3SJana Rapava 	return ULPI_ERROR;
229f93022c3SJana Rapava }
2303e6e809fSGovindraj.R int ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
2313e6e809fSGovindraj.R 	__attribute__((weak, alias("__ulpi_reset_wait")));
232f93022c3SJana Rapava 
ulpi_reset(struct ulpi_viewport * ulpi_vp)2333e6e809fSGovindraj.R int ulpi_reset(struct ulpi_viewport *ulpi_vp)
234f93022c3SJana Rapava {
2354256101fSIgor Grinberg 	int err;
236f93022c3SJana Rapava 
2373e6e809fSGovindraj.R 	err = ulpi_write(ulpi_vp,
238f93022c3SJana Rapava 			&ulpi->function_ctrl_set, ULPI_FC_RESET);
239f93022c3SJana Rapava 	if (err) {
240f93022c3SJana Rapava 		printf("ULPI: %s: failed writing reset bit\n", __func__);
241f93022c3SJana Rapava 		return err;
242f93022c3SJana Rapava 	}
243f93022c3SJana Rapava 
2443e6e809fSGovindraj.R 	return ulpi_reset_wait(ulpi_vp);
245f93022c3SJana Rapava }
246