xref: /OK3568_Linux_fs/u-boot/drivers/usb/host/r8a66597-hcd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * R8A66597 HCD (Host Controller Driver) for u-boot
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2008  Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <console.h>
11*4882a593Smuzhiyun #include <dm.h>
12*4882a593Smuzhiyun #include <usb.h>
13*4882a593Smuzhiyun #include <asm/io.h>
14*4882a593Smuzhiyun #include <linux/iopoll.h>
15*4882a593Smuzhiyun #include <power/regulator.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "r8a66597.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #ifdef R8A66597_DEBUG
20*4882a593Smuzhiyun #define R8A66597_DPRINT		printf
21*4882a593Smuzhiyun #else
22*4882a593Smuzhiyun #define R8A66597_DPRINT(...)
23*4882a593Smuzhiyun #endif
24*4882a593Smuzhiyun 
usb_dev_get_parent(struct usb_device * udev)25*4882a593Smuzhiyun static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	struct udevice *parent = udev->dev->parent;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	/*
30*4882a593Smuzhiyun 	 * When called from usb-uclass.c: usb_scan_device() udev->dev points
31*4882a593Smuzhiyun 	 * to the parent udevice, not the actual udevice belonging to the
32*4882a593Smuzhiyun 	 * udev as the device is not instantiated yet.
33*4882a593Smuzhiyun 	 *
34*4882a593Smuzhiyun 	 * If dev is an usb-bus, then we are called from usb_scan_device() for
35*4882a593Smuzhiyun 	 * an usb-device plugged directly into the root port, return NULL.
36*4882a593Smuzhiyun 	 */
37*4882a593Smuzhiyun 	if (device_get_uclass_id(udev->dev) == UCLASS_USB)
38*4882a593Smuzhiyun 		return NULL;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	/*
41*4882a593Smuzhiyun 	 * If these 2 are not the same we are being called from
42*4882a593Smuzhiyun 	 * usb_scan_device() and udev itself is the parent.
43*4882a593Smuzhiyun 	 */
44*4882a593Smuzhiyun 	if (dev_get_parent_priv(udev->dev) != udev)
45*4882a593Smuzhiyun 		return udev;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	/* We are being called normally, use the parent pointer */
48*4882a593Smuzhiyun 	if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
49*4882a593Smuzhiyun 		return dev_get_parent_priv(parent);
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	return NULL;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun 
get_hub_data(struct usb_device * dev,u16 * hub_devnum,u16 * hubport)54*4882a593Smuzhiyun static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	struct usb_device *parent = usb_dev_get_parent(dev);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	*hub_devnum = 0;
59*4882a593Smuzhiyun 	*hubport = 0;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	/* check a device connected to root_hub */
62*4882a593Smuzhiyun 	if ((parent && parent->devnum == 1) ||
63*4882a593Smuzhiyun 	    dev->devnum == 1)
64*4882a593Smuzhiyun 		return;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	*hub_devnum = (u8)parent->devnum;
67*4882a593Smuzhiyun 	*hubport = parent->portnr - 1;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
set_devadd(struct r8a66597 * r8a66597,u8 r8a66597_address,struct usb_device * dev,int port)70*4882a593Smuzhiyun static void set_devadd(struct r8a66597 *r8a66597, u8 r8a66597_address,
71*4882a593Smuzhiyun 		       struct usb_device *dev, int port)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	u16 val, usbspd, upphub, hubport;
74*4882a593Smuzhiyun 	unsigned long devadd_reg = get_devadd_addr(r8a66597_address);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	get_hub_data(dev, &upphub, &hubport);
77*4882a593Smuzhiyun 	usbspd = r8a66597->speed;
78*4882a593Smuzhiyun 	val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001);
79*4882a593Smuzhiyun 	r8a66597_write(r8a66597, val, devadd_reg);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
r8a66597_clock_enable(struct r8a66597 * r8a66597)82*4882a593Smuzhiyun static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	u16 tmp;
85*4882a593Smuzhiyun 	int i = 0;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	do {
88*4882a593Smuzhiyun 		r8a66597_write(r8a66597, USBE, SYSCFG0);
89*4882a593Smuzhiyun 		tmp = r8a66597_read(r8a66597, SYSCFG0);
90*4882a593Smuzhiyun 		if (i++ > 1000) {
91*4882a593Smuzhiyun 			printf("register access fail.\n");
92*4882a593Smuzhiyun 			return -1;
93*4882a593Smuzhiyun 		}
94*4882a593Smuzhiyun 	} while ((tmp & USBE) != USBE);
95*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, USBE, SYSCFG0);
96*4882a593Smuzhiyun 	/*
97*4882a593Smuzhiyun 	 * RZ/A Only:
98*4882a593Smuzhiyun 	 * Bits XTAL(UCKSEL) and UPLLE in SYSCFG0 for USB0 controls both USB0
99*4882a593Smuzhiyun 	 * and USB1, so we must always set the USB0 register
100*4882a593Smuzhiyun 	 */
101*4882a593Smuzhiyun #if (CONFIG_R8A66597_XTAL == 1)
102*4882a593Smuzhiyun 	setbits(le16, R8A66597_BASE0, XTAL);
103*4882a593Smuzhiyun #endif
104*4882a593Smuzhiyun 	mdelay(1);
105*4882a593Smuzhiyun 	setbits(le16, R8A66597_BASE0, UPLLE);
106*4882a593Smuzhiyun 	mdelay(1);
107*4882a593Smuzhiyun 	r8a66597_bset(r8a66597, SUSPM, SUSPMODE0);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
r8a66597_clock_disable(struct r8a66597 * r8a66597)112*4882a593Smuzhiyun static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, SUSPM, SUSPMODE0);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	clrbits(le16, R8A66597_BASE0, UPLLE);
117*4882a593Smuzhiyun 	mdelay(1);
118*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, USBE, SYSCFG0);
119*4882a593Smuzhiyun 	mdelay(1);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
r8a66597_enable_port(struct r8a66597 * r8a66597,int port)122*4882a593Smuzhiyun static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	u16 val;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	val = port ? DRPD : DCFM | DRPD;
127*4882a593Smuzhiyun 	r8a66597_bset(r8a66597, val, get_syscfg_reg(port));
128*4882a593Smuzhiyun 	r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
r8a66597_disable_port(struct r8a66597 * r8a66597,int port)131*4882a593Smuzhiyun static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	u16 val, tmp;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, get_intenb_reg(port));
136*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, get_intsts_reg(port));
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	r8a66597_port_power(r8a66597, port, 0);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	do {
141*4882a593Smuzhiyun 		tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
142*4882a593Smuzhiyun 		udelay(640);
143*4882a593Smuzhiyun 	} while (tmp == EDGESTS);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	val = port ? DRPD : DCFM | DRPD;
146*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, val, get_syscfg_reg(port));
147*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
enable_controller(struct r8a66597 * r8a66597)150*4882a593Smuzhiyun static int enable_controller(struct r8a66597 *r8a66597)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	int ret, port;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	ret = r8a66597_clock_enable(r8a66597);
155*4882a593Smuzhiyun 	if (ret < 0)
156*4882a593Smuzhiyun 		return ret;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	r8a66597_bset(r8a66597, USBE, SYSCFG0);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	r8a66597_bset(r8a66597, INTL, SOFCFG);
161*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, INTENB0);
162*4882a593Smuzhiyun 	for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
163*4882a593Smuzhiyun 		r8a66597_write(r8a66597, 0, get_intenb_reg(port));
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, BIGEND, CFIFOSEL);
166*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, BIGEND, D0FIFOSEL);
167*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, BIGEND, D1FIFOSEL);
168*4882a593Smuzhiyun 	r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
171*4882a593Smuzhiyun 		r8a66597_enable_port(r8a66597, port);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	return 0;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
disable_controller(struct r8a66597 * r8a66597)176*4882a593Smuzhiyun static void disable_controller(struct r8a66597 *r8a66597)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	int i;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	if (!(r8a66597_read(r8a66597, SYSCFG0) & USBE))
181*4882a593Smuzhiyun 		return;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, INTENB0);
184*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, INTSTS0);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, D0FIFOSEL);
187*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, D1FIFOSEL);
188*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, DCPCFG);
189*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0x40, DCPMAXP);
190*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, DCPCTR);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	for (i = 0; i <= 10; i++)
193*4882a593Smuzhiyun 		r8a66597_write(r8a66597, 0, get_devadd_addr(i));
194*4882a593Smuzhiyun 	for (i = 1; i <= 5; i++) {
195*4882a593Smuzhiyun 		r8a66597_write(r8a66597, 0, get_pipetre_addr(i));
196*4882a593Smuzhiyun 		r8a66597_write(r8a66597, 0, get_pipetrn_addr(i));
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 	for (i = 1; i < R8A66597_MAX_NUM_PIPE; i++) {
199*4882a593Smuzhiyun 		r8a66597_write(r8a66597, 0, get_pipectr_addr(i));
200*4882a593Smuzhiyun 		r8a66597_write(r8a66597, i, PIPESEL);
201*4882a593Smuzhiyun 		r8a66597_write(r8a66597, 0, PIPECFG);
202*4882a593Smuzhiyun 		r8a66597_write(r8a66597, 0, PIPEBUF);
203*4882a593Smuzhiyun 		r8a66597_write(r8a66597, 0, PIPEMAXP);
204*4882a593Smuzhiyun 		r8a66597_write(r8a66597, 0, PIPEPERI);
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++)
208*4882a593Smuzhiyun 		r8a66597_disable_port(r8a66597, i);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	r8a66597_clock_disable(r8a66597);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
r8a66597_reg_wait(struct r8a66597 * r8a66597,unsigned long reg,u16 mask,u16 loop)213*4882a593Smuzhiyun static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
214*4882a593Smuzhiyun 			      u16 mask, u16 loop)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	u16 tmp;
217*4882a593Smuzhiyun 	int i = 0;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	do {
220*4882a593Smuzhiyun 		tmp = r8a66597_read(r8a66597, reg);
221*4882a593Smuzhiyun 		if (i++ > 1000000) {
222*4882a593Smuzhiyun 			printf("register%lx, loop %x is timeout\n", reg, loop);
223*4882a593Smuzhiyun 			break;
224*4882a593Smuzhiyun 		}
225*4882a593Smuzhiyun 	} while ((tmp & mask) != loop);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
pipe_buffer_setting(struct r8a66597 * r8a66597,struct usb_device * dev,unsigned long pipe)228*4882a593Smuzhiyun static void pipe_buffer_setting(struct r8a66597 *r8a66597,
229*4882a593Smuzhiyun 				struct usb_device *dev, unsigned long pipe)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	u16 val = 0;
232*4882a593Smuzhiyun 	u16 pipenum, bufnum, maxpacket;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	if (usb_pipein(pipe)) {
235*4882a593Smuzhiyun 		pipenum = BULK_IN_PIPENUM;
236*4882a593Smuzhiyun 		bufnum = BULK_IN_BUFNUM;
237*4882a593Smuzhiyun 		maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
238*4882a593Smuzhiyun 	} else {
239*4882a593Smuzhiyun 		pipenum = BULK_OUT_PIPENUM;
240*4882a593Smuzhiyun 		bufnum = BULK_OUT_BUFNUM;
241*4882a593Smuzhiyun 		maxpacket = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (r8a66597->pipe_config & (1 << pipenum))
245*4882a593Smuzhiyun 		return;
246*4882a593Smuzhiyun 	r8a66597->pipe_config |= (1 << pipenum);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(pipenum));
249*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(pipenum));
250*4882a593Smuzhiyun 	r8a66597_write(r8a66597, pipenum, PIPESEL);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	/* FIXME: This driver support bulk transfer only. */
253*4882a593Smuzhiyun 	if (!usb_pipein(pipe))
254*4882a593Smuzhiyun 		val |= R8A66597_DIR;
255*4882a593Smuzhiyun 	else
256*4882a593Smuzhiyun 		val |= R8A66597_SHTNAK;
257*4882a593Smuzhiyun 	val |= R8A66597_BULK | R8A66597_DBLB | usb_pipeendpoint(pipe);
258*4882a593Smuzhiyun 	r8a66597_write(r8a66597, val, PIPECFG);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	r8a66597_write(r8a66597, (8 << 10) | bufnum, PIPEBUF);
261*4882a593Smuzhiyun 	r8a66597_write(r8a66597, make_devsel(usb_pipedevice(pipe)) |
262*4882a593Smuzhiyun 				 maxpacket, PIPEMAXP);
263*4882a593Smuzhiyun 	r8a66597_write(r8a66597, 0, PIPEPERI);
264*4882a593Smuzhiyun 	r8a66597_write(r8a66597, SQCLR, get_pipectr_addr(pipenum));
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
send_setup_packet(struct r8a66597 * r8a66597,struct usb_device * dev,struct devrequest * setup)267*4882a593Smuzhiyun static int send_setup_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
268*4882a593Smuzhiyun 			     struct devrequest *setup)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	int i;
271*4882a593Smuzhiyun 	unsigned short *p = (unsigned short *)setup;
272*4882a593Smuzhiyun 	unsigned long setup_addr = USBREQ;
273*4882a593Smuzhiyun 	u16 intsts1;
274*4882a593Smuzhiyun 	int timeout = 3000;
275*4882a593Smuzhiyun 	u16 dcpctr;
276*4882a593Smuzhiyun 	u16 devsel = setup->request == USB_REQ_SET_ADDRESS ? 0 : dev->devnum;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	r8a66597_write(r8a66597, make_devsel(devsel) |
279*4882a593Smuzhiyun 				 (8 << dev->maxpacketsize), DCPMAXP);
280*4882a593Smuzhiyun 	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	dcpctr = r8a66597_read(r8a66597, DCPCTR);
283*4882a593Smuzhiyun 	if ((dcpctr & PID) == PID_BUF) {
284*4882a593Smuzhiyun 		if (readw_poll_timeout(r8a66597->reg + DCPCTR, dcpctr,
285*4882a593Smuzhiyun 				       dcpctr & BSTS, 1000) < 0) {
286*4882a593Smuzhiyun 			printf("DCPCTR BSTS timeout!\n");
287*4882a593Smuzhiyun 			return -ETIMEDOUT;
288*4882a593Smuzhiyun 		}
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
292*4882a593Smuzhiyun 		r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr);
293*4882a593Smuzhiyun 		setup_addr += 2;
294*4882a593Smuzhiyun 	}
295*4882a593Smuzhiyun 	r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
296*4882a593Smuzhiyun 	r8a66597_write(r8a66597, SUREQ, DCPCTR);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	while (1) {
299*4882a593Smuzhiyun 		intsts1 = r8a66597_read(r8a66597, INTSTS1);
300*4882a593Smuzhiyun 		if (intsts1 & SACK)
301*4882a593Smuzhiyun 			break;
302*4882a593Smuzhiyun 		if (intsts1 & SIGN) {
303*4882a593Smuzhiyun 			printf("setup packet send error\n");
304*4882a593Smuzhiyun 			return -1;
305*4882a593Smuzhiyun 		}
306*4882a593Smuzhiyun 		if (timeout-- < 0) {
307*4882a593Smuzhiyun 			printf("setup packet timeout\n");
308*4882a593Smuzhiyun 			return -1;
309*4882a593Smuzhiyun 		}
310*4882a593Smuzhiyun 		udelay(500);
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	return 0;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
send_bulk_packet(struct r8a66597 * r8a66597,struct usb_device * dev,unsigned long pipe,void * buffer,int transfer_len)316*4882a593Smuzhiyun static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
317*4882a593Smuzhiyun 			    unsigned long pipe, void *buffer, int transfer_len)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	u16 tmp, bufsize;
320*4882a593Smuzhiyun 	u16 *buf;
321*4882a593Smuzhiyun 	size_t size;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	R8A66597_DPRINT("%s\n", __func__);
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, MBW | BULK_OUT_PIPENUM,
326*4882a593Smuzhiyun 		      MBW | CURPIPE, CFIFOSEL);
327*4882a593Smuzhiyun 	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, BULK_OUT_PIPENUM);
328*4882a593Smuzhiyun 	tmp = r8a66597_read(r8a66597, CFIFOCTR);
329*4882a593Smuzhiyun 	if ((tmp & FRDY) == 0) {
330*4882a593Smuzhiyun 		printf("%s FRDY is not set (%x)\n", __func__, tmp);
331*4882a593Smuzhiyun 		return -1;
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	/* prepare parameters */
335*4882a593Smuzhiyun 	bufsize = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
336*4882a593Smuzhiyun 	buf = (u16 *)(buffer + dev->act_len);
337*4882a593Smuzhiyun 	size = min((int)bufsize, transfer_len - dev->act_len);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	/* write fifo */
340*4882a593Smuzhiyun 	r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
341*4882a593Smuzhiyun 	if (buffer) {
342*4882a593Smuzhiyun 		r8a66597_write_fifo(r8a66597, CFIFO, buf, size);
343*4882a593Smuzhiyun 		r8a66597_write(r8a66597, BVAL, CFIFOCTR);
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	/* update parameters */
347*4882a593Smuzhiyun 	dev->act_len += size;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, PID_BUF, PID,
350*4882a593Smuzhiyun 		      get_pipectr_addr(BULK_OUT_PIPENUM));
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	while (!(r8a66597_read(r8a66597, BEMPSTS) & (1 << BULK_OUT_PIPENUM)))
353*4882a593Smuzhiyun 		if (ctrlc())
354*4882a593Smuzhiyun 			return -1;
355*4882a593Smuzhiyun 	r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	if (dev->act_len >= transfer_len)
358*4882a593Smuzhiyun 		r8a66597_mdfy(r8a66597, PID_NAK, PID,
359*4882a593Smuzhiyun 			      get_pipectr_addr(BULK_OUT_PIPENUM));
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	return 0;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun 
receive_bulk_packet(struct r8a66597 * r8a66597,struct usb_device * dev,unsigned long pipe,void * buffer,int transfer_len)364*4882a593Smuzhiyun static int receive_bulk_packet(struct r8a66597 *r8a66597,
365*4882a593Smuzhiyun 			       struct usb_device *dev,
366*4882a593Smuzhiyun 			       unsigned long pipe,
367*4882a593Smuzhiyun 			       void *buffer, int transfer_len)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun 	u16 tmp;
370*4882a593Smuzhiyun 	u16 *buf;
371*4882a593Smuzhiyun 	const u16 pipenum = BULK_IN_PIPENUM;
372*4882a593Smuzhiyun 	int rcv_len;
373*4882a593Smuzhiyun 	int maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	R8A66597_DPRINT("%s\n", __func__);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	/* prepare */
378*4882a593Smuzhiyun 	if (dev->act_len == 0) {
379*4882a593Smuzhiyun 		r8a66597_mdfy(r8a66597, PID_NAK, PID,
380*4882a593Smuzhiyun 			      get_pipectr_addr(pipenum));
381*4882a593Smuzhiyun 		r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 		r8a66597_write(r8a66597, TRCLR, get_pipetre_addr(pipenum));
384*4882a593Smuzhiyun 		r8a66597_write(r8a66597,
385*4882a593Smuzhiyun 			       (transfer_len + maxpacket - 1) / maxpacket,
386*4882a593Smuzhiyun 				get_pipetrn_addr(pipenum));
387*4882a593Smuzhiyun 		r8a66597_bset(r8a66597, TRENB, get_pipetre_addr(pipenum));
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 		r8a66597_mdfy(r8a66597, PID_BUF, PID,
390*4882a593Smuzhiyun 			      get_pipectr_addr(pipenum));
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
394*4882a593Smuzhiyun 	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	while (!(r8a66597_read(r8a66597, BRDYSTS) & (1 << pipenum)))
397*4882a593Smuzhiyun 		if (ctrlc())
398*4882a593Smuzhiyun 			return -1;
399*4882a593Smuzhiyun 	r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	tmp = r8a66597_read(r8a66597, CFIFOCTR);
402*4882a593Smuzhiyun 	if ((tmp & FRDY) == 0) {
403*4882a593Smuzhiyun 		printf("%s FRDY is not set. (%x)\n", __func__, tmp);
404*4882a593Smuzhiyun 		return -1;
405*4882a593Smuzhiyun 	}
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	buf = (u16 *)(buffer + dev->act_len);
408*4882a593Smuzhiyun 	rcv_len = tmp & DTLN;
409*4882a593Smuzhiyun 	dev->act_len += rcv_len;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	if (buffer) {
412*4882a593Smuzhiyun 		if (rcv_len == 0)
413*4882a593Smuzhiyun 			r8a66597_write(r8a66597, BCLR, CFIFOCTR);
414*4882a593Smuzhiyun 		else
415*4882a593Smuzhiyun 			r8a66597_read_fifo(r8a66597, CFIFO, buf, rcv_len);
416*4882a593Smuzhiyun 	}
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	return 0;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
receive_control_packet(struct r8a66597 * r8a66597,struct usb_device * dev,void * buffer,int transfer_len)421*4882a593Smuzhiyun static int receive_control_packet(struct r8a66597 *r8a66597,
422*4882a593Smuzhiyun 				  struct usb_device *dev,
423*4882a593Smuzhiyun 				  void *buffer, int transfer_len)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	u16 tmp;
426*4882a593Smuzhiyun 	int rcv_len;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	/* FIXME: limit transfer size : 64byte or less */
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
431*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
432*4882a593Smuzhiyun 	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
433*4882a593Smuzhiyun 	r8a66597_bset(r8a66597, SQSET, DCPCTR);
434*4882a593Smuzhiyun 	r8a66597_write(r8a66597, BCLR, CFIFOCTR);
435*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	while (!(r8a66597_read(r8a66597, BRDYSTS) & 0x0001))
438*4882a593Smuzhiyun 		if (ctrlc())
439*4882a593Smuzhiyun 			return -1;
440*4882a593Smuzhiyun 	r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, MBW, MBW | CURPIPE, CFIFOSEL);
443*4882a593Smuzhiyun 	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	tmp = r8a66597_read(r8a66597, CFIFOCTR);
446*4882a593Smuzhiyun 	if ((tmp & FRDY) == 0) {
447*4882a593Smuzhiyun 		printf("%s FRDY is not set. (%x)\n", __func__, tmp);
448*4882a593Smuzhiyun 		return -1;
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	rcv_len = tmp & DTLN;
452*4882a593Smuzhiyun 	dev->act_len += rcv_len;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	if (buffer) {
457*4882a593Smuzhiyun 		if (rcv_len == 0)
458*4882a593Smuzhiyun 			r8a66597_write(r8a66597, BCLR, DCPCTR);
459*4882a593Smuzhiyun 		else
460*4882a593Smuzhiyun 			r8a66597_read_fifo(r8a66597, CFIFO, buffer, rcv_len);
461*4882a593Smuzhiyun 	}
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	return 0;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun 
send_status_packet(struct r8a66597 * r8a66597,unsigned long pipe)466*4882a593Smuzhiyun static int send_status_packet(struct r8a66597 *r8a66597,
467*4882a593Smuzhiyun 			      unsigned long pipe)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun 	r8a66597_bset(r8a66597, SQSET, DCPCTR);
470*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	if (usb_pipein(pipe)) {
473*4882a593Smuzhiyun 		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
474*4882a593Smuzhiyun 		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
475*4882a593Smuzhiyun 		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
476*4882a593Smuzhiyun 		r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
477*4882a593Smuzhiyun 		r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
478*4882a593Smuzhiyun 	} else {
479*4882a593Smuzhiyun 		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
480*4882a593Smuzhiyun 		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
481*4882a593Smuzhiyun 		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
482*4882a593Smuzhiyun 		r8a66597_write(r8a66597, BCLR, CFIFOCTR);
483*4882a593Smuzhiyun 	}
484*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	while (!(r8a66597_read(r8a66597, BEMPSTS) & 0x0001))
487*4882a593Smuzhiyun 		if (ctrlc())
488*4882a593Smuzhiyun 			return -1;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	return 0;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun 
r8a66597_check_syssts(struct r8a66597 * r8a66597,int port)493*4882a593Smuzhiyun static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	int count = R8A66597_MAX_SAMPLING;
496*4882a593Smuzhiyun 	unsigned short syssts, old_syssts;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	R8A66597_DPRINT("%s\n", __func__);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
501*4882a593Smuzhiyun 	while (count > 0) {
502*4882a593Smuzhiyun 		mdelay(R8A66597_RH_POLL_TIME);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 		syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
505*4882a593Smuzhiyun 		if (syssts == old_syssts) {
506*4882a593Smuzhiyun 			count--;
507*4882a593Smuzhiyun 		} else {
508*4882a593Smuzhiyun 			count = R8A66597_MAX_SAMPLING;
509*4882a593Smuzhiyun 			old_syssts = syssts;
510*4882a593Smuzhiyun 		}
511*4882a593Smuzhiyun 	}
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun 
r8a66597_bus_reset(struct r8a66597 * r8a66597,int port)514*4882a593Smuzhiyun static void r8a66597_bus_reset(struct r8a66597 *r8a66597, int port)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun 	mdelay(10);
517*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, get_dvstctr_reg(port));
518*4882a593Smuzhiyun 	mdelay(50);
519*4882a593Smuzhiyun 	r8a66597_mdfy(r8a66597, UACT, USBRST | UACT, get_dvstctr_reg(port));
520*4882a593Smuzhiyun 	mdelay(50);
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun 
check_usb_device_connecting(struct r8a66597 * r8a66597)523*4882a593Smuzhiyun static int check_usb_device_connecting(struct r8a66597 *r8a66597)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun 	int timeout = 10000;	/* 100usec * 10000 = 1sec */
526*4882a593Smuzhiyun 	int i;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	for (i = 0; i < 5; i++) {
529*4882a593Smuzhiyun 		/* check a usb cable connect */
530*4882a593Smuzhiyun 		while (!(r8a66597_read(r8a66597, INTSTS1) & ATTCH)) {
531*4882a593Smuzhiyun 			if (timeout-- < 0) {
532*4882a593Smuzhiyun 				printf("%s timeout.\n", __func__);
533*4882a593Smuzhiyun 				return -1;
534*4882a593Smuzhiyun 			}
535*4882a593Smuzhiyun 			udelay(100);
536*4882a593Smuzhiyun 		}
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 		/* check a data line */
539*4882a593Smuzhiyun 		r8a66597_check_syssts(r8a66597, 0);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 		r8a66597_bus_reset(r8a66597, 0);
542*4882a593Smuzhiyun 		r8a66597->speed = get_rh_usb_speed(r8a66597, 0);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 		if (!(r8a66597_read(r8a66597, INTSTS1) & DTCH)) {
545*4882a593Smuzhiyun 			r8a66597->port_change = USB_PORT_STAT_C_CONNECTION;
546*4882a593Smuzhiyun 			r8a66597->port_status = USB_PORT_STAT_CONNECTION |
547*4882a593Smuzhiyun 						USB_PORT_STAT_ENABLE;
548*4882a593Smuzhiyun 			return 0;	/* success */
549*4882a593Smuzhiyun 		}
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 		R8A66597_DPRINT("USB device has detached. retry = %d\n", i);
552*4882a593Smuzhiyun 		r8a66597_write(r8a66597, ~DTCH, INTSTS1);
553*4882a593Smuzhiyun 	}
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	return -1;	/* fail */
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun /* Virtual Root Hub */
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun #include <usbroothubdes.h>
561*4882a593Smuzhiyun 
r8a66597_submit_rh_msg(struct udevice * udev,struct usb_device * dev,unsigned long pipe,void * buffer,int transfer_len,struct devrequest * cmd)562*4882a593Smuzhiyun static int r8a66597_submit_rh_msg(struct udevice *udev, struct usb_device *dev,
563*4882a593Smuzhiyun 				  unsigned long pipe, void *buffer,
564*4882a593Smuzhiyun 				  int transfer_len, struct devrequest *cmd)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun 	struct r8a66597 *r8a66597 = dev_get_priv(udev);
567*4882a593Smuzhiyun 	int leni = transfer_len;
568*4882a593Smuzhiyun 	int len = 0;
569*4882a593Smuzhiyun 	int stat = 0;
570*4882a593Smuzhiyun 	__u16 bmRType_bReq;
571*4882a593Smuzhiyun 	__u16 wValue;
572*4882a593Smuzhiyun 	__u16 wLength;
573*4882a593Smuzhiyun 	unsigned char data[32];
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	R8A66597_DPRINT("%s\n", __func__);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	if (usb_pipeint(pipe)) {
578*4882a593Smuzhiyun 		printf("Root-Hub submit IRQ: NOT implemented");
579*4882a593Smuzhiyun 		return 0;
580*4882a593Smuzhiyun 	}
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
583*4882a593Smuzhiyun 	wValue	      = cpu_to_le16 (cmd->value);
584*4882a593Smuzhiyun 	wLength	      = cpu_to_le16 (cmd->length);
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	switch (bmRType_bReq) {
587*4882a593Smuzhiyun 	case RH_GET_STATUS:
588*4882a593Smuzhiyun 		*(__u16 *)buffer = cpu_to_le16(1);
589*4882a593Smuzhiyun 		len = 2;
590*4882a593Smuzhiyun 		break;
591*4882a593Smuzhiyun 	case RH_GET_STATUS | RH_INTERFACE:
592*4882a593Smuzhiyun 		*(__u16 *)buffer = cpu_to_le16(0);
593*4882a593Smuzhiyun 		len = 2;
594*4882a593Smuzhiyun 		break;
595*4882a593Smuzhiyun 	case RH_GET_STATUS | RH_ENDPOINT:
596*4882a593Smuzhiyun 		*(__u16 *)buffer = cpu_to_le16(0);
597*4882a593Smuzhiyun 		len = 2;
598*4882a593Smuzhiyun 		break;
599*4882a593Smuzhiyun 	case RH_GET_STATUS | RH_CLASS:
600*4882a593Smuzhiyun 		*(__u32 *)buffer = cpu_to_le32(0);
601*4882a593Smuzhiyun 		len = 4;
602*4882a593Smuzhiyun 		break;
603*4882a593Smuzhiyun 	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
604*4882a593Smuzhiyun 		*(__u32 *)buffer = cpu_to_le32(r8a66597->port_status |
605*4882a593Smuzhiyun 						(r8a66597->port_change << 16));
606*4882a593Smuzhiyun 		len = 4;
607*4882a593Smuzhiyun 		break;
608*4882a593Smuzhiyun 	case RH_CLEAR_FEATURE | RH_ENDPOINT:
609*4882a593Smuzhiyun 	case RH_CLEAR_FEATURE | RH_CLASS:
610*4882a593Smuzhiyun 		break;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
613*4882a593Smuzhiyun 		switch (wValue) {
614*4882a593Smuzhiyun 		case RH_C_PORT_CONNECTION:
615*4882a593Smuzhiyun 			r8a66597->port_change &= ~USB_PORT_STAT_C_CONNECTION;
616*4882a593Smuzhiyun 			break;
617*4882a593Smuzhiyun 		}
618*4882a593Smuzhiyun 		break;
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
621*4882a593Smuzhiyun 		switch (wValue) {
622*4882a593Smuzhiyun 		case (RH_PORT_SUSPEND):
623*4882a593Smuzhiyun 			break;
624*4882a593Smuzhiyun 		case (RH_PORT_RESET):
625*4882a593Smuzhiyun 			r8a66597_bus_reset(r8a66597, 0);
626*4882a593Smuzhiyun 			break;
627*4882a593Smuzhiyun 		case (RH_PORT_POWER):
628*4882a593Smuzhiyun 			break;
629*4882a593Smuzhiyun 		case (RH_PORT_ENABLE):
630*4882a593Smuzhiyun 			break;
631*4882a593Smuzhiyun 		}
632*4882a593Smuzhiyun 		break;
633*4882a593Smuzhiyun 	case RH_SET_ADDRESS:
634*4882a593Smuzhiyun 		r8a66597->rh_devnum = wValue;
635*4882a593Smuzhiyun 		break;
636*4882a593Smuzhiyun 	case RH_GET_DESCRIPTOR:
637*4882a593Smuzhiyun 		switch ((wValue & 0xff00) >> 8) {
638*4882a593Smuzhiyun 		case (0x01): /* device descriptor */
639*4882a593Smuzhiyun 			len = min_t(unsigned int,
640*4882a593Smuzhiyun 				    leni,
641*4882a593Smuzhiyun 				  min_t(unsigned int,
642*4882a593Smuzhiyun 					sizeof(root_hub_dev_des),
643*4882a593Smuzhiyun 				      wLength));
644*4882a593Smuzhiyun 			memcpy(buffer, root_hub_dev_des, len);
645*4882a593Smuzhiyun 			break;
646*4882a593Smuzhiyun 		case (0x02): /* configuration descriptor */
647*4882a593Smuzhiyun 			len = min_t(unsigned int,
648*4882a593Smuzhiyun 				    leni,
649*4882a593Smuzhiyun 				  min_t(unsigned int,
650*4882a593Smuzhiyun 					sizeof(root_hub_config_des),
651*4882a593Smuzhiyun 				      wLength));
652*4882a593Smuzhiyun 			memcpy(buffer, root_hub_config_des, len);
653*4882a593Smuzhiyun 			break;
654*4882a593Smuzhiyun 		case (0x03): /* string descriptors */
655*4882a593Smuzhiyun 			if (wValue == 0x0300) {
656*4882a593Smuzhiyun 				len = min_t(unsigned int,
657*4882a593Smuzhiyun 					    leni,
658*4882a593Smuzhiyun 					  min_t(unsigned int,
659*4882a593Smuzhiyun 						sizeof(root_hub_str_index0),
660*4882a593Smuzhiyun 					      wLength));
661*4882a593Smuzhiyun 				memcpy(buffer, root_hub_str_index0, len);
662*4882a593Smuzhiyun 			}
663*4882a593Smuzhiyun 			if (wValue == 0x0301) {
664*4882a593Smuzhiyun 				len = min_t(unsigned int,
665*4882a593Smuzhiyun 					    leni,
666*4882a593Smuzhiyun 					  min_t(unsigned int,
667*4882a593Smuzhiyun 						sizeof(root_hub_str_index1),
668*4882a593Smuzhiyun 					      wLength));
669*4882a593Smuzhiyun 				memcpy(buffer, root_hub_str_index1, len);
670*4882a593Smuzhiyun 			}
671*4882a593Smuzhiyun 			break;
672*4882a593Smuzhiyun 		default:
673*4882a593Smuzhiyun 			stat = USB_ST_STALLED;
674*4882a593Smuzhiyun 		}
675*4882a593Smuzhiyun 		break;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	case RH_GET_DESCRIPTOR | RH_CLASS:
678*4882a593Smuzhiyun 	{
679*4882a593Smuzhiyun 		__u32 temp = 0x00000001;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 		data[0] = 9;		/* min length; */
682*4882a593Smuzhiyun 		data[1] = 0x29;
683*4882a593Smuzhiyun 		data[2] = temp & RH_A_NDP;
684*4882a593Smuzhiyun 		data[3] = 0;
685*4882a593Smuzhiyun 		if (temp & RH_A_PSM)
686*4882a593Smuzhiyun 			data[3] |= 0x1;
687*4882a593Smuzhiyun 		if (temp & RH_A_NOCP)
688*4882a593Smuzhiyun 			data[3] |= 0x10;
689*4882a593Smuzhiyun 		else if (temp & RH_A_OCPM)
690*4882a593Smuzhiyun 			data[3] |= 0x8;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 		/* corresponds to data[4-7] */
693*4882a593Smuzhiyun 		data[5] = (temp & RH_A_POTPGT) >> 24;
694*4882a593Smuzhiyun 		data[7] = temp & RH_B_DR;
695*4882a593Smuzhiyun 		if (data[2] < 7) {
696*4882a593Smuzhiyun 			data[8] = 0xff;
697*4882a593Smuzhiyun 		} else {
698*4882a593Smuzhiyun 			data[0] += 2;
699*4882a593Smuzhiyun 			data[8] = (temp & RH_B_DR) >> 8;
700*4882a593Smuzhiyun 			data[9] = 0xff;
701*4882a593Smuzhiyun 			data[10] = 0xff;
702*4882a593Smuzhiyun 		}
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 		len = min_t(unsigned int, leni,
705*4882a593Smuzhiyun 			    min_t(unsigned int, data[0], wLength));
706*4882a593Smuzhiyun 		memcpy(buffer, data, len);
707*4882a593Smuzhiyun 		break;
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	case RH_GET_CONFIGURATION:
711*4882a593Smuzhiyun 		*(__u8 *)buffer = 0x01;
712*4882a593Smuzhiyun 		len = 1;
713*4882a593Smuzhiyun 		break;
714*4882a593Smuzhiyun 	case RH_SET_CONFIGURATION:
715*4882a593Smuzhiyun 		break;
716*4882a593Smuzhiyun 	default:
717*4882a593Smuzhiyun 		R8A66597_DPRINT("unsupported root hub command");
718*4882a593Smuzhiyun 		stat = USB_ST_STALLED;
719*4882a593Smuzhiyun 	}
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	mdelay(1);
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	len = min_t(int, len, leni);
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	dev->act_len = len;
726*4882a593Smuzhiyun 	dev->status = stat;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	return stat;
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun 
r8a66597_submit_control_msg(struct udevice * udev,struct usb_device * dev,unsigned long pipe,void * buffer,int length,struct devrequest * setup)731*4882a593Smuzhiyun static int r8a66597_submit_control_msg(struct udevice *udev,
732*4882a593Smuzhiyun 				       struct usb_device *dev,
733*4882a593Smuzhiyun 				       unsigned long pipe, void *buffer,
734*4882a593Smuzhiyun 				       int length, struct devrequest *setup)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun 	struct r8a66597 *r8a66597 = dev_get_priv(udev);
737*4882a593Smuzhiyun 	u16 r8a66597_address = setup->request == USB_REQ_SET_ADDRESS ?
738*4882a593Smuzhiyun 					0 : dev->devnum;
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
741*4882a593Smuzhiyun 	      udev->name, dev, dev->dev->name, dev->portnr);
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	R8A66597_DPRINT("%s\n", __func__);
744*4882a593Smuzhiyun 	if (usb_pipedevice(pipe) == r8a66597->rh_devnum)
745*4882a593Smuzhiyun 		return r8a66597_submit_rh_msg(udev, dev, pipe, buffer,
746*4882a593Smuzhiyun 					      length, setup);
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	R8A66597_DPRINT("%s: setup\n", __func__);
749*4882a593Smuzhiyun 	set_devadd(r8a66597, r8a66597_address, dev, 0);
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	if (send_setup_packet(r8a66597, dev, setup) < 0) {
752*4882a593Smuzhiyun 		printf("setup packet send error\n");
753*4882a593Smuzhiyun 		return -1;
754*4882a593Smuzhiyun 	}
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	dev->act_len = 0;
757*4882a593Smuzhiyun 	if (usb_pipein(pipe))
758*4882a593Smuzhiyun 		if (receive_control_packet(r8a66597, dev, buffer,
759*4882a593Smuzhiyun 					   length) < 0)
760*4882a593Smuzhiyun 			return -1;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	if (send_status_packet(r8a66597, pipe) < 0)
763*4882a593Smuzhiyun 		return -1;
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	dev->status = 0;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	return 0;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun 
r8a66597_submit_bulk_msg(struct udevice * udev,struct usb_device * dev,unsigned long pipe,void * buffer,int length)770*4882a593Smuzhiyun static int r8a66597_submit_bulk_msg(struct udevice *udev,
771*4882a593Smuzhiyun 				    struct usb_device *dev, unsigned long pipe,
772*4882a593Smuzhiyun 				    void *buffer, int length)
773*4882a593Smuzhiyun {
774*4882a593Smuzhiyun 	struct r8a66597 *r8a66597 = dev_get_priv(udev);
775*4882a593Smuzhiyun 	int ret = 0;
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	debug("%s: dev='%s', udev=%p\n", __func__, udev->name, dev);
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	R8A66597_DPRINT("%s\n", __func__);
780*4882a593Smuzhiyun 	R8A66597_DPRINT("pipe = %08x, buffer = %p, len = %d, devnum = %d\n",
781*4882a593Smuzhiyun 			pipe, buffer, length, dev->devnum);
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	set_devadd(r8a66597, dev->devnum, dev, 0);
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	pipe_buffer_setting(r8a66597, dev, pipe);
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	dev->act_len = 0;
788*4882a593Smuzhiyun 	while (dev->act_len < length && ret == 0) {
789*4882a593Smuzhiyun 		if (ctrlc())
790*4882a593Smuzhiyun 			return -1;
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 		if (usb_pipein(pipe))
793*4882a593Smuzhiyun 			ret = receive_bulk_packet(r8a66597, dev, pipe, buffer,
794*4882a593Smuzhiyun 						  length);
795*4882a593Smuzhiyun 		else
796*4882a593Smuzhiyun 			ret = send_bulk_packet(r8a66597, dev, pipe, buffer,
797*4882a593Smuzhiyun 					       length);
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	if (ret == 0)
801*4882a593Smuzhiyun 		dev->status = 0;
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	return ret;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun 
r8a66597_usb_ofdata_to_platdata(struct udevice * dev)806*4882a593Smuzhiyun static int r8a66597_usb_ofdata_to_platdata(struct udevice *dev)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun 	struct r8a66597 *priv = dev_get_priv(dev);
809*4882a593Smuzhiyun 	fdt_addr_t addr;
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	addr = dev_read_addr(dev);
812*4882a593Smuzhiyun 	if (addr == FDT_ADDR_T_NONE)
813*4882a593Smuzhiyun 		return -EINVAL;
814*4882a593Smuzhiyun 	priv->reg = addr;
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	return 0;
817*4882a593Smuzhiyun }
818*4882a593Smuzhiyun 
r8a66597_usb_probe(struct udevice * dev)819*4882a593Smuzhiyun static int r8a66597_usb_probe(struct udevice *dev)
820*4882a593Smuzhiyun {
821*4882a593Smuzhiyun 	struct r8a66597 *priv = dev_get_priv(dev);
822*4882a593Smuzhiyun 	struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev);
823*4882a593Smuzhiyun 	int ret;
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	bus_priv->desc_before_addr = true;
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
828*4882a593Smuzhiyun 		ret = device_get_supply_regulator(dev, "vbus-supply",
829*4882a593Smuzhiyun 						  &priv->vbus_supply);
830*4882a593Smuzhiyun 		if (ret) {
831*4882a593Smuzhiyun 			dev_err(dev,
832*4882a593Smuzhiyun 				"can't get VBUS supply\n");
833*4882a593Smuzhiyun 			return ret;
834*4882a593Smuzhiyun 		}
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 		ret = regulator_set_enable(priv->vbus_supply, true);
837*4882a593Smuzhiyun 		if (ret) {
838*4882a593Smuzhiyun 			dev_err(dev,
839*4882a593Smuzhiyun 				"can't enable VBUS supply\n");
840*4882a593Smuzhiyun 			return ret;
841*4882a593Smuzhiyun 		}
842*4882a593Smuzhiyun 	}
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	disable_controller(priv);
845*4882a593Smuzhiyun 	mdelay(100);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	enable_controller(priv);
848*4882a593Smuzhiyun 	r8a66597_port_power(priv, 0, 1);
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	/* check usb device */
851*4882a593Smuzhiyun 	check_usb_device_connecting(priv);
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	mdelay(50);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	return 0;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
r8a66597_usb_remove(struct udevice * dev)858*4882a593Smuzhiyun static int r8a66597_usb_remove(struct udevice *dev)
859*4882a593Smuzhiyun {
860*4882a593Smuzhiyun 	struct r8a66597 *priv = dev_get_priv(dev);
861*4882a593Smuzhiyun 	int ret;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	disable_controller(priv);
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
866*4882a593Smuzhiyun 		ret = regulator_set_enable(priv->vbus_supply, false);
867*4882a593Smuzhiyun 		if (ret) {
868*4882a593Smuzhiyun 			dev_err(dev,
869*4882a593Smuzhiyun 				"can't disable VBUS supply\n");
870*4882a593Smuzhiyun 			return ret;
871*4882a593Smuzhiyun 		}
872*4882a593Smuzhiyun 	}
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	return 0;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun struct dm_usb_ops r8a66597_usb_ops = {
878*4882a593Smuzhiyun 	.control = r8a66597_submit_control_msg,
879*4882a593Smuzhiyun 	.bulk = r8a66597_submit_bulk_msg,
880*4882a593Smuzhiyun };
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun static const struct udevice_id r8a66597_usb_ids[] = {
883*4882a593Smuzhiyun 	{ .compatible = "renesas,rza1-usbhs" },
884*4882a593Smuzhiyun 	{ }
885*4882a593Smuzhiyun };
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun U_BOOT_DRIVER(usb_r8a66597) = {
888*4882a593Smuzhiyun 	.name	= "r8a66597_usb",
889*4882a593Smuzhiyun 	.id	= UCLASS_USB,
890*4882a593Smuzhiyun 	.of_match = r8a66597_usb_ids,
891*4882a593Smuzhiyun 	.ofdata_to_platdata = r8a66597_usb_ofdata_to_platdata,
892*4882a593Smuzhiyun 	.probe	= r8a66597_usb_probe,
893*4882a593Smuzhiyun 	.remove = r8a66597_usb_remove,
894*4882a593Smuzhiyun 	.ops	= &r8a66597_usb_ops,
895*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct r8a66597),
896*4882a593Smuzhiyun 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
897*4882a593Smuzhiyun };
898