xref: /openbmc/u-boot/drivers/usb/musb-new/sunxi.c (revision 28a15ef7fd7d97f0634440866c6b7baa7708b5eb)
1*28a15ef7SHans de Goede /*
2*28a15ef7SHans de Goede  * Allwinner SUNXI "glue layer"
3*28a15ef7SHans de Goede  *
4*28a15ef7SHans de Goede  * Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
5*28a15ef7SHans de Goede  * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
6*28a15ef7SHans de Goede  *
7*28a15ef7SHans de Goede  * Based on the sw_usb "Allwinner OTG Dual Role Controller" code.
8*28a15ef7SHans de Goede  *  Copyright 2007-2012 (C) Allwinner Technology Co., Ltd.
9*28a15ef7SHans de Goede  *  javen <javen@allwinnertech.com>
10*28a15ef7SHans de Goede  *
11*28a15ef7SHans de Goede  * Based on the DA8xx "glue layer" code.
12*28a15ef7SHans de Goede  *  Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
13*28a15ef7SHans de Goede  *  Copyright (C) 2005-2006 by Texas Instruments
14*28a15ef7SHans de Goede  *
15*28a15ef7SHans de Goede  * This file is part of the Inventra Controller Driver for Linux.
16*28a15ef7SHans de Goede  *
17*28a15ef7SHans de Goede  * The Inventra Controller Driver for Linux is free software; you
18*28a15ef7SHans de Goede  * can redistribute it and/or modify it under the terms of the GNU
19*28a15ef7SHans de Goede  * General Public License version 2 as published by the Free Software
20*28a15ef7SHans de Goede  * Foundation.
21*28a15ef7SHans de Goede  *
22*28a15ef7SHans de Goede  */
23*28a15ef7SHans de Goede #include <common.h>
24*28a15ef7SHans de Goede #include <asm/arch/cpu.h>
25*28a15ef7SHans de Goede #include <asm/arch/usbc.h>
26*28a15ef7SHans de Goede #include "linux-compat.h"
27*28a15ef7SHans de Goede #include "musb_core.h"
28*28a15ef7SHans de Goede 
29*28a15ef7SHans de Goede /******************************************************************************
30*28a15ef7SHans de Goede  ******************************************************************************
31*28a15ef7SHans de Goede  * From the Allwinner driver
32*28a15ef7SHans de Goede  ******************************************************************************
33*28a15ef7SHans de Goede  ******************************************************************************/
34*28a15ef7SHans de Goede 
35*28a15ef7SHans de Goede /******************************************************************************
36*28a15ef7SHans de Goede  * From include/sunxi_usb_bsp.h
37*28a15ef7SHans de Goede  ******************************************************************************/
38*28a15ef7SHans de Goede 
39*28a15ef7SHans de Goede /* reg offsets */
40*28a15ef7SHans de Goede #define  USBC_REG_o_ISCR	0x0400
41*28a15ef7SHans de Goede #define  USBC_REG_o_PHYCTL	0x0404
42*28a15ef7SHans de Goede #define  USBC_REG_o_PHYBIST	0x0408
43*28a15ef7SHans de Goede #define  USBC_REG_o_PHYTUNE	0x040c
44*28a15ef7SHans de Goede 
45*28a15ef7SHans de Goede #define  USBC_REG_o_VEND0	0x0043
46*28a15ef7SHans de Goede 
47*28a15ef7SHans de Goede /* Interface Status and Control */
48*28a15ef7SHans de Goede #define  USBC_BP_ISCR_VBUS_VALID_FROM_DATA	30
49*28a15ef7SHans de Goede #define  USBC_BP_ISCR_VBUS_VALID_FROM_VBUS	29
50*28a15ef7SHans de Goede #define  USBC_BP_ISCR_EXT_ID_STATUS		28
51*28a15ef7SHans de Goede #define  USBC_BP_ISCR_EXT_DM_STATUS		27
52*28a15ef7SHans de Goede #define  USBC_BP_ISCR_EXT_DP_STATUS		26
53*28a15ef7SHans de Goede #define  USBC_BP_ISCR_MERGED_VBUS_STATUS	25
54*28a15ef7SHans de Goede #define  USBC_BP_ISCR_MERGED_ID_STATUS		24
55*28a15ef7SHans de Goede 
56*28a15ef7SHans de Goede #define  USBC_BP_ISCR_ID_PULLUP_EN		17
57*28a15ef7SHans de Goede #define  USBC_BP_ISCR_DPDM_PULLUP_EN		16
58*28a15ef7SHans de Goede #define  USBC_BP_ISCR_FORCE_ID			14
59*28a15ef7SHans de Goede #define  USBC_BP_ISCR_FORCE_VBUS_VALID		12
60*28a15ef7SHans de Goede #define  USBC_BP_ISCR_VBUS_VALID_SRC		10
61*28a15ef7SHans de Goede 
62*28a15ef7SHans de Goede #define  USBC_BP_ISCR_HOSC_EN			7
63*28a15ef7SHans de Goede #define  USBC_BP_ISCR_VBUS_CHANGE_DETECT	6
64*28a15ef7SHans de Goede #define  USBC_BP_ISCR_ID_CHANGE_DETECT		5
65*28a15ef7SHans de Goede #define  USBC_BP_ISCR_DPDM_CHANGE_DETECT	4
66*28a15ef7SHans de Goede #define  USBC_BP_ISCR_IRQ_ENABLE		3
67*28a15ef7SHans de Goede #define  USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN	2
68*28a15ef7SHans de Goede #define  USBC_BP_ISCR_ID_CHANGE_DETECT_EN	1
69*28a15ef7SHans de Goede #define  USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN	0
70*28a15ef7SHans de Goede 
71*28a15ef7SHans de Goede /******************************************************************************
72*28a15ef7SHans de Goede  * From usbc/usbc.c
73*28a15ef7SHans de Goede  ******************************************************************************/
74*28a15ef7SHans de Goede 
75*28a15ef7SHans de Goede static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val)
76*28a15ef7SHans de Goede {
77*28a15ef7SHans de Goede 	u32 temp = reg_val;
78*28a15ef7SHans de Goede 
79*28a15ef7SHans de Goede 	temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT);
80*28a15ef7SHans de Goede 	temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT);
81*28a15ef7SHans de Goede 	temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT);
82*28a15ef7SHans de Goede 
83*28a15ef7SHans de Goede 	return temp;
84*28a15ef7SHans de Goede }
85*28a15ef7SHans de Goede 
86*28a15ef7SHans de Goede static void USBC_EnableIdPullUp(__iomem void *base)
87*28a15ef7SHans de Goede {
88*28a15ef7SHans de Goede 	u32 reg_val;
89*28a15ef7SHans de Goede 
90*28a15ef7SHans de Goede 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
91*28a15ef7SHans de Goede 	reg_val |= (1 << USBC_BP_ISCR_ID_PULLUP_EN);
92*28a15ef7SHans de Goede 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
93*28a15ef7SHans de Goede 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
94*28a15ef7SHans de Goede }
95*28a15ef7SHans de Goede 
96*28a15ef7SHans de Goede static void USBC_DisableIdPullUp(__iomem void *base)
97*28a15ef7SHans de Goede {
98*28a15ef7SHans de Goede 	u32 reg_val;
99*28a15ef7SHans de Goede 
100*28a15ef7SHans de Goede 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
101*28a15ef7SHans de Goede 	reg_val &= ~(1 << USBC_BP_ISCR_ID_PULLUP_EN);
102*28a15ef7SHans de Goede 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
103*28a15ef7SHans de Goede 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
104*28a15ef7SHans de Goede }
105*28a15ef7SHans de Goede 
106*28a15ef7SHans de Goede static void USBC_EnableDpDmPullUp(__iomem void *base)
107*28a15ef7SHans de Goede {
108*28a15ef7SHans de Goede 	u32 reg_val;
109*28a15ef7SHans de Goede 
110*28a15ef7SHans de Goede 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
111*28a15ef7SHans de Goede 	reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
112*28a15ef7SHans de Goede 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
113*28a15ef7SHans de Goede 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
114*28a15ef7SHans de Goede }
115*28a15ef7SHans de Goede 
116*28a15ef7SHans de Goede static void USBC_DisableDpDmPullUp(__iomem void *base)
117*28a15ef7SHans de Goede {
118*28a15ef7SHans de Goede 	u32 reg_val;
119*28a15ef7SHans de Goede 
120*28a15ef7SHans de Goede 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
121*28a15ef7SHans de Goede 	reg_val &= ~(1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
122*28a15ef7SHans de Goede 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
123*28a15ef7SHans de Goede 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
124*28a15ef7SHans de Goede }
125*28a15ef7SHans de Goede 
126*28a15ef7SHans de Goede static void USBC_ForceIdToLow(__iomem void *base)
127*28a15ef7SHans de Goede {
128*28a15ef7SHans de Goede 	u32 reg_val;
129*28a15ef7SHans de Goede 
130*28a15ef7SHans de Goede 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
131*28a15ef7SHans de Goede 	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
132*28a15ef7SHans de Goede 	reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID);
133*28a15ef7SHans de Goede 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
134*28a15ef7SHans de Goede 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
135*28a15ef7SHans de Goede }
136*28a15ef7SHans de Goede 
137*28a15ef7SHans de Goede static void USBC_ForceIdToHigh(__iomem void *base)
138*28a15ef7SHans de Goede {
139*28a15ef7SHans de Goede 	u32 reg_val;
140*28a15ef7SHans de Goede 
141*28a15ef7SHans de Goede 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
142*28a15ef7SHans de Goede 	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
143*28a15ef7SHans de Goede 	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
144*28a15ef7SHans de Goede 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
145*28a15ef7SHans de Goede 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
146*28a15ef7SHans de Goede }
147*28a15ef7SHans de Goede 
148*28a15ef7SHans de Goede static void USBC_ForceVbusValidDisable(__iomem void *base)
149*28a15ef7SHans de Goede {
150*28a15ef7SHans de Goede 	u32 reg_val;
151*28a15ef7SHans de Goede 
152*28a15ef7SHans de Goede 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
153*28a15ef7SHans de Goede 	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
154*28a15ef7SHans de Goede 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
155*28a15ef7SHans de Goede 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
156*28a15ef7SHans de Goede }
157*28a15ef7SHans de Goede 
158*28a15ef7SHans de Goede static void USBC_ForceVbusValidToHigh(__iomem void *base)
159*28a15ef7SHans de Goede {
160*28a15ef7SHans de Goede 	u32 reg_val;
161*28a15ef7SHans de Goede 
162*28a15ef7SHans de Goede 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
163*28a15ef7SHans de Goede 	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
164*28a15ef7SHans de Goede 	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
165*28a15ef7SHans de Goede 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
166*28a15ef7SHans de Goede 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
167*28a15ef7SHans de Goede }
168*28a15ef7SHans de Goede 
169*28a15ef7SHans de Goede static void USBC_ConfigFIFO_Base(void)
170*28a15ef7SHans de Goede {
171*28a15ef7SHans de Goede 	u32 reg_value;
172*28a15ef7SHans de Goede 
173*28a15ef7SHans de Goede 	/* config usb fifo, 8kb mode */
174*28a15ef7SHans de Goede 	reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
175*28a15ef7SHans de Goede 	reg_value &= ~(0x03 << 0);
176*28a15ef7SHans de Goede 	reg_value |= (1 << 0);
177*28a15ef7SHans de Goede 	writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
178*28a15ef7SHans de Goede }
179*28a15ef7SHans de Goede 
180*28a15ef7SHans de Goede /******************************************************************************
181*28a15ef7SHans de Goede  * MUSB Glue code
182*28a15ef7SHans de Goede  ******************************************************************************/
183*28a15ef7SHans de Goede 
184*28a15ef7SHans de Goede static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
185*28a15ef7SHans de Goede {
186*28a15ef7SHans de Goede 	struct musb		*musb = __hci;
187*28a15ef7SHans de Goede 	irqreturn_t		retval = IRQ_NONE;
188*28a15ef7SHans de Goede 
189*28a15ef7SHans de Goede 	/* read and flush interrupts */
190*28a15ef7SHans de Goede 	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
191*28a15ef7SHans de Goede 	if (musb->int_usb)
192*28a15ef7SHans de Goede 		musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
193*28a15ef7SHans de Goede 	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
194*28a15ef7SHans de Goede 	if (musb->int_tx)
195*28a15ef7SHans de Goede 		musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
196*28a15ef7SHans de Goede 	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
197*28a15ef7SHans de Goede 	if (musb->int_rx)
198*28a15ef7SHans de Goede 		musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
199*28a15ef7SHans de Goede 
200*28a15ef7SHans de Goede 	if (musb->int_usb || musb->int_tx || musb->int_rx)
201*28a15ef7SHans de Goede 		retval |= musb_interrupt(musb);
202*28a15ef7SHans de Goede 
203*28a15ef7SHans de Goede 	return retval;
204*28a15ef7SHans de Goede }
205*28a15ef7SHans de Goede 
206*28a15ef7SHans de Goede static void sunxi_musb_enable(struct musb *musb)
207*28a15ef7SHans de Goede {
208*28a15ef7SHans de Goede 	pr_debug("%s():\n", __func__);
209*28a15ef7SHans de Goede 
210*28a15ef7SHans de Goede 	/* select PIO mode */
211*28a15ef7SHans de Goede 	musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
212*28a15ef7SHans de Goede 
213*28a15ef7SHans de Goede 	if (is_host_enabled(musb)) {
214*28a15ef7SHans de Goede 		/* port power on */
215*28a15ef7SHans de Goede 		sunxi_usbc_vbus_enable(0);
216*28a15ef7SHans de Goede 	}
217*28a15ef7SHans de Goede }
218*28a15ef7SHans de Goede 
219*28a15ef7SHans de Goede static void sunxi_musb_disable(struct musb *musb)
220*28a15ef7SHans de Goede {
221*28a15ef7SHans de Goede 	pr_debug("%s():\n", __func__);
222*28a15ef7SHans de Goede 
223*28a15ef7SHans de Goede 	/* Put the controller back in a pristane state for "usb reset" */
224*28a15ef7SHans de Goede 	if (musb->is_active) {
225*28a15ef7SHans de Goede 		sunxi_usbc_disable(0);
226*28a15ef7SHans de Goede 		sunxi_usbc_enable(0);
227*28a15ef7SHans de Goede 		musb->is_active = 0;
228*28a15ef7SHans de Goede 	}
229*28a15ef7SHans de Goede }
230*28a15ef7SHans de Goede 
231*28a15ef7SHans de Goede static int sunxi_musb_init(struct musb *musb)
232*28a15ef7SHans de Goede {
233*28a15ef7SHans de Goede 	int err;
234*28a15ef7SHans de Goede 
235*28a15ef7SHans de Goede 	pr_debug("%s():\n", __func__);
236*28a15ef7SHans de Goede 
237*28a15ef7SHans de Goede 	err = sunxi_usbc_request_resources(0);
238*28a15ef7SHans de Goede 	if (err)
239*28a15ef7SHans de Goede 		return err;
240*28a15ef7SHans de Goede 
241*28a15ef7SHans de Goede 	musb->isr = sunxi_musb_interrupt;
242*28a15ef7SHans de Goede 	sunxi_usbc_enable(0);
243*28a15ef7SHans de Goede 
244*28a15ef7SHans de Goede 	USBC_ConfigFIFO_Base();
245*28a15ef7SHans de Goede 	USBC_EnableDpDmPullUp(musb->mregs);
246*28a15ef7SHans de Goede 	USBC_EnableIdPullUp(musb->mregs);
247*28a15ef7SHans de Goede 
248*28a15ef7SHans de Goede 	if (is_host_enabled(musb)) {
249*28a15ef7SHans de Goede 		/* Host mode */
250*28a15ef7SHans de Goede 		USBC_ForceIdToLow(musb->mregs);
251*28a15ef7SHans de Goede 		USBC_ForceVbusValidToHigh(musb->mregs);
252*28a15ef7SHans de Goede 	} else {
253*28a15ef7SHans de Goede 		/* Peripheral mode */
254*28a15ef7SHans de Goede 		USBC_ForceIdToHigh(musb->mregs);
255*28a15ef7SHans de Goede 		USBC_ForceVbusValidDisable(musb->mregs);
256*28a15ef7SHans de Goede 	}
257*28a15ef7SHans de Goede 
258*28a15ef7SHans de Goede 	return 0;
259*28a15ef7SHans de Goede }
260*28a15ef7SHans de Goede 
261*28a15ef7SHans de Goede static int sunxi_musb_exit(struct musb *musb)
262*28a15ef7SHans de Goede {
263*28a15ef7SHans de Goede 	pr_debug("%s():\n", __func__);
264*28a15ef7SHans de Goede 
265*28a15ef7SHans de Goede 	USBC_DisableDpDmPullUp(musb->mregs);
266*28a15ef7SHans de Goede 	USBC_DisableIdPullUp(musb->mregs);
267*28a15ef7SHans de Goede 	sunxi_usbc_vbus_disable(0);
268*28a15ef7SHans de Goede 	sunxi_usbc_disable(0);
269*28a15ef7SHans de Goede 
270*28a15ef7SHans de Goede 	return sunxi_usbc_free_resources(0);
271*28a15ef7SHans de Goede }
272*28a15ef7SHans de Goede 
273*28a15ef7SHans de Goede const struct musb_platform_ops sunxi_musb_ops = {
274*28a15ef7SHans de Goede 	.init		= sunxi_musb_init,
275*28a15ef7SHans de Goede 	.exit		= sunxi_musb_exit,
276*28a15ef7SHans de Goede 
277*28a15ef7SHans de Goede 	.enable		= sunxi_musb_enable,
278*28a15ef7SHans de Goede 	.disable	= sunxi_musb_disable,
279*28a15ef7SHans de Goede };
280