1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Allwinner SUNXI "glue layer"
4 *
5 * Copyright �� 2015 Hans de Goede <hdegoede@redhat.com>
6 * Copyright �� 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
7 *
8 * Based on the sw_usb "Allwinner OTG Dual Role Controller" code.
9 *  Copyright 2007-2012 (C) Allwinner Technology Co., Ltd.
10 *  javen <javen@allwinnertech.com>
11 *
12 * Based on the DA8xx "glue layer" code.
13 *  Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
14 *  Copyright (C) 2005-2006 by Texas Instruments
15 *
16 * This file is part of the Inventra Controller Driver for Linux.
17 */
18#include <common.h>
19#include <clk.h>
20#include <dm.h>
21#include <generic-phy.h>
22#include <log.h>
23#include <malloc.h>
24#include <phy-sun4i-usb.h>
25#include <reset.h>
26#include <asm/arch/cpu.h>
27#include <asm/arch/clock.h>
28#include <dm/device_compat.h>
29#include <dm/lists.h>
30#include <dm/root.h>
31#include <linux/bitops.h>
32#include <linux/delay.h>
33#include <linux/printk.h>
34#include <linux/usb/musb.h>
35#include "linux-compat.h"
36#include "musb_core.h"
37#include "musb_uboot.h"
38
39/******************************************************************************
40 ******************************************************************************
41 * From the Allwinner driver
42 ******************************************************************************
43 ******************************************************************************/
44
45/******************************************************************************
46 * From include/sunxi_usb_bsp.h
47 ******************************************************************************/
48
49/* reg offsets */
50#define  USBC_REG_o_ISCR	0x0400
51#define  USBC_REG_o_PHYCTL	0x0404
52#define  USBC_REG_o_PHYBIST	0x0408
53#define  USBC_REG_o_PHYTUNE	0x040c
54
55#define  USBC_REG_o_VEND0	0x0043
56
57/* Interface Status and Control */
58#define  USBC_BP_ISCR_VBUS_VALID_FROM_DATA	30
59#define  USBC_BP_ISCR_VBUS_VALID_FROM_VBUS	29
60#define  USBC_BP_ISCR_EXT_ID_STATUS		28
61#define  USBC_BP_ISCR_EXT_DM_STATUS		27
62#define  USBC_BP_ISCR_EXT_DP_STATUS		26
63#define  USBC_BP_ISCR_MERGED_VBUS_STATUS	25
64#define  USBC_BP_ISCR_MERGED_ID_STATUS		24
65
66#define  USBC_BP_ISCR_ID_PULLUP_EN		17
67#define  USBC_BP_ISCR_DPDM_PULLUP_EN		16
68#define  USBC_BP_ISCR_FORCE_ID			14
69#define  USBC_BP_ISCR_FORCE_VBUS_VALID		12
70#define  USBC_BP_ISCR_VBUS_VALID_SRC		10
71
72#define  USBC_BP_ISCR_HOSC_EN			7
73#define  USBC_BP_ISCR_VBUS_CHANGE_DETECT	6
74#define  USBC_BP_ISCR_ID_CHANGE_DETECT		5
75#define  USBC_BP_ISCR_DPDM_CHANGE_DETECT	4
76#define  USBC_BP_ISCR_IRQ_ENABLE		3
77#define  USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN	2
78#define  USBC_BP_ISCR_ID_CHANGE_DETECT_EN	1
79#define  USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN	0
80
81/******************************************************************************
82 * From usbc/usbc.c
83 ******************************************************************************/
84
85struct sunxi_musb_config {
86	struct musb_hdrc_config *config;
87};
88
89struct sunxi_glue {
90	struct musb_host_data mdata;
91	struct clk clk;
92	struct reset_ctl rst;
93	struct sunxi_musb_config *cfg;
94	struct device dev;
95	struct phy phy;
96};
97#define to_sunxi_glue(d)	container_of(d, struct sunxi_glue, dev)
98
99static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val)
100{
101	u32 temp = reg_val;
102
103	temp &= ~BIT(USBC_BP_ISCR_VBUS_CHANGE_DETECT);
104	temp &= ~BIT(USBC_BP_ISCR_ID_CHANGE_DETECT);
105	temp &= ~BIT(USBC_BP_ISCR_DPDM_CHANGE_DETECT);
106
107	return temp;
108}
109
110static void USBC_EnableIdPullUp(__iomem void *base)
111{
112	u32 reg_val;
113
114	reg_val = musb_readl(base, USBC_REG_o_ISCR);
115	reg_val |= BIT(USBC_BP_ISCR_ID_PULLUP_EN);
116	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
117	musb_writel(base, USBC_REG_o_ISCR, reg_val);
118}
119
120static void USBC_EnableDpDmPullUp(__iomem void *base)
121{
122	u32 reg_val;
123
124	reg_val = musb_readl(base, USBC_REG_o_ISCR);
125	reg_val |= BIT(USBC_BP_ISCR_DPDM_PULLUP_EN);
126	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
127	musb_writel(base, USBC_REG_o_ISCR, reg_val);
128}
129
130static void USBC_ForceIdToLow(__iomem void *base)
131{
132	u32 reg_val;
133
134	reg_val = musb_readl(base, USBC_REG_o_ISCR);
135	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
136	reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID);
137	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
138	musb_writel(base, USBC_REG_o_ISCR, reg_val);
139}
140
141static void USBC_ForceIdToHigh(__iomem void *base)
142{
143	u32 reg_val;
144
145	reg_val = musb_readl(base, USBC_REG_o_ISCR);
146	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
147	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
148	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
149	musb_writel(base, USBC_REG_o_ISCR, reg_val);
150}
151
152static void USBC_ForceVbusValidToLow(__iomem void *base)
153{
154	u32 reg_val;
155
156	reg_val = musb_readl(base, USBC_REG_o_ISCR);
157	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
158	reg_val |= (0x02 << USBC_BP_ISCR_FORCE_VBUS_VALID);
159	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
160	musb_writel(base, USBC_REG_o_ISCR, reg_val);
161}
162
163static void USBC_ForceVbusValidToHigh(__iomem void *base)
164{
165	u32 reg_val;
166
167	reg_val = musb_readl(base, USBC_REG_o_ISCR);
168	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
169	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
170	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
171	musb_writel(base, USBC_REG_o_ISCR, reg_val);
172}
173
174static void USBC_ConfigFIFO_Base(void)
175{
176	u32 reg_value;
177
178	/* config usb fifo, 8kb mode */
179	reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
180	reg_value &= ~(0x03 << 0);
181	reg_value |= BIT(0);
182	writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
183}
184
185/******************************************************************************
186 * Needed for the DFU polling magic
187 ******************************************************************************/
188
189static u8 last_int_usb;
190
191bool dfu_usb_get_reset(void)
192{
193	return !!(last_int_usb & MUSB_INTR_RESET);
194}
195
196/******************************************************************************
197 * MUSB Glue code
198 ******************************************************************************/
199
200static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
201{
202	struct musb		*musb = __hci;
203	irqreturn_t		retval = IRQ_NONE;
204
205	/* read and flush interrupts */
206	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
207	last_int_usb = musb->int_usb;
208	if (musb->int_usb)
209		musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
210	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
211	if (musb->int_tx)
212		musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
213	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
214	if (musb->int_rx)
215		musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
216
217	if (musb->int_usb || musb->int_tx || musb->int_rx)
218		retval |= musb_interrupt(musb);
219
220	return retval;
221}
222
223/* musb_core does not call enable / disable in a balanced manner <sigh> */
224static bool enabled = false;
225
226static int sunxi_musb_enable(struct musb *musb)
227{
228	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
229	int ret;
230
231	pr_debug("%s():\n", __func__);
232
233	musb_ep_select(musb->mregs, 0);
234	musb_writeb(musb->mregs, MUSB_FADDR, 0);
235
236	if (enabled)
237		return 0;
238
239	/* select PIO mode */
240	musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
241
242	if (is_host_enabled(musb)) {
243		ret = sun4i_usb_phy_id_detect(&glue->phy);
244		if (ret == 1) {
245			printf("No host cable detected: ");
246			return -ENODEV;
247		}
248
249		ret = generic_phy_power_on(&glue->phy);
250		if (ret) {
251			pr_debug("failed to power on USB PHY\n");
252			return ret;
253		}
254	}
255
256	USBC_ForceVbusValidToHigh(musb->mregs);
257
258	enabled = true;
259	return 0;
260}
261
262static void sunxi_musb_disable(struct musb *musb)
263{
264	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
265	int ret;
266
267	pr_debug("%s():\n", __func__);
268
269	if (!enabled)
270		return;
271
272	if (is_host_enabled(musb)) {
273		ret = generic_phy_power_off(&glue->phy);
274		if (ret) {
275			pr_debug("failed to power off USB PHY\n");
276			return;
277		}
278	}
279
280	USBC_ForceVbusValidToLow(musb->mregs);
281	mdelay(200); /* Wait for the current session to timeout */
282
283	enabled = false;
284}
285
286static int sunxi_musb_init(struct musb *musb)
287{
288	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
289	int ret;
290
291	pr_debug("%s():\n", __func__);
292
293	ret = clk_enable(&glue->clk);
294	if (ret) {
295		dev_err(musb->controller, "failed to enable clock\n");
296		return ret;
297	}
298
299	if (reset_valid(&glue->rst)) {
300		ret = reset_deassert(&glue->rst);
301		if (ret) {
302			dev_err(musb->controller, "failed to deassert reset\n");
303			goto err_clk;
304		}
305	}
306
307	ret = generic_phy_init(&glue->phy);
308	if (ret) {
309		dev_dbg(musb->controller, "failed to init USB PHY\n");
310		goto err_rst;
311	}
312
313	musb->isr = sunxi_musb_interrupt;
314
315	USBC_ConfigFIFO_Base();
316	USBC_EnableDpDmPullUp(musb->mregs);
317	USBC_EnableIdPullUp(musb->mregs);
318
319	if (is_host_enabled(musb)) {
320		/* Host mode */
321		USBC_ForceIdToLow(musb->mregs);
322	} else {
323		/* Peripheral mode */
324		USBC_ForceIdToHigh(musb->mregs);
325	}
326	USBC_ForceVbusValidToHigh(musb->mregs);
327
328	return 0;
329
330err_rst:
331	if (reset_valid(&glue->rst))
332		reset_assert(&glue->rst);
333err_clk:
334	clk_disable(&glue->clk);
335	return ret;
336}
337
338static int sunxi_musb_exit(struct musb *musb)
339{
340	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
341	int ret = 0;
342
343	if (generic_phy_valid(&glue->phy)) {
344		ret = generic_phy_exit(&glue->phy);
345		if (ret) {
346			dev_dbg(musb->controller,
347				"failed to power off usb phy\n");
348			return ret;
349		}
350	}
351
352	if (reset_valid(&glue->rst))
353		reset_assert(&glue->rst);
354	clk_disable(&glue->clk);
355
356	return 0;
357}
358
359static void sunxi_musb_pre_root_reset_end(struct musb *musb)
360{
361	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
362
363	sun4i_usb_phy_set_squelch_detect(&glue->phy, false);
364}
365
366static void sunxi_musb_post_root_reset_end(struct musb *musb)
367{
368	struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
369
370	sun4i_usb_phy_set_squelch_detect(&glue->phy, true);
371}
372
373static const struct musb_platform_ops sunxi_musb_ops = {
374	.init		= sunxi_musb_init,
375	.exit		= sunxi_musb_exit,
376	.enable		= sunxi_musb_enable,
377	.disable	= sunxi_musb_disable,
378	.pre_root_reset_end = sunxi_musb_pre_root_reset_end,
379	.post_root_reset_end = sunxi_musb_post_root_reset_end,
380};
381
382/* Allwinner OTG supports up to 5 endpoints */
383#define SUNXI_MUSB_MAX_EP_NUM		6
384#define SUNXI_MUSB_RAM_BITS		11
385
386static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = {
387	MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
388	MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
389	MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
390	MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
391	MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
392	MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
393	MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
394	MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
395	MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512),
396	MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512),
397};
398
399/* H3/V3s OTG supports only 4 endpoints */
400#define SUNXI_MUSB_MAX_EP_NUM_H3	5
401
402static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = {
403	MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
404	MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
405	MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
406	MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
407	MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
408	MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
409	MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
410	MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
411};
412
413static struct musb_hdrc_config musb_config = {
414	.fifo_cfg       = sunxi_musb_mode_cfg,
415	.fifo_cfg_size  = ARRAY_SIZE(sunxi_musb_mode_cfg),
416	.multipoint	= true,
417	.dyn_fifo	= true,
418	.num_eps	= SUNXI_MUSB_MAX_EP_NUM,
419	.ram_bits	= SUNXI_MUSB_RAM_BITS,
420};
421
422static struct musb_hdrc_config musb_config_h3 = {
423	.fifo_cfg       = sunxi_musb_mode_cfg_h3,
424	.fifo_cfg_size  = ARRAY_SIZE(sunxi_musb_mode_cfg_h3),
425	.multipoint	= true,
426	.dyn_fifo	= true,
427	.soft_con       = true,
428	.num_eps	= SUNXI_MUSB_MAX_EP_NUM_H3,
429	.ram_bits	= SUNXI_MUSB_RAM_BITS,
430};
431
432static int musb_usb_probe(struct udevice *dev)
433{
434	struct sunxi_glue *glue = dev_get_priv(dev);
435	struct musb_host_data *host = &glue->mdata;
436	struct musb_hdrc_platform_data pdata;
437	void *base = dev_read_addr_ptr(dev);
438	int ret;
439
440#ifdef CONFIG_USB_MUSB_HOST
441	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
442#endif
443
444	if (!base)
445		return -EINVAL;
446
447	glue->cfg = (struct sunxi_musb_config *)dev_get_driver_data(dev);
448	if (!glue->cfg)
449		return -EINVAL;
450
451	ret = clk_get_by_index(dev, 0, &glue->clk);
452	if (ret) {
453		dev_err(dev, "failed to get clock\n");
454		return ret;
455	}
456
457	ret = reset_get_by_index(dev, 0, &glue->rst);
458	if (ret && ret != -ENOENT) {
459		dev_err(dev, "failed to get reset\n");
460		return ret;
461	}
462
463	ret = generic_phy_get_by_name(dev, "usb", &glue->phy);
464	if (ret) {
465		pr_err("failed to get usb PHY\n");
466		return ret;
467	}
468
469	memset(&pdata, 0, sizeof(pdata));
470	pdata.power = 250;
471	pdata.platform_ops = &sunxi_musb_ops;
472	pdata.config = glue->cfg->config;
473
474#ifdef CONFIG_USB_MUSB_HOST
475	priv->desc_before_addr = true;
476
477	pdata.mode = MUSB_HOST;
478	host->host = musb_init_controller(&pdata, &glue->dev, base);
479	if (!host->host)
480		return -EIO;
481
482	ret = musb_lowlevel_init(host);
483	if (!ret)
484		printf("Allwinner mUSB OTG (Host)\n");
485#else
486	pdata.mode = MUSB_PERIPHERAL;
487	host->host = musb_register(&pdata, &glue->dev, base);
488	if (IS_ERR_OR_NULL(host->host))
489		return -EIO;
490
491	printf("Allwinner mUSB OTG (Peripheral)\n");
492#endif
493
494	return ret;
495}
496
497static int musb_usb_remove(struct udevice *dev)
498{
499	struct sunxi_glue *glue = dev_get_priv(dev);
500	struct musb_host_data *host = &glue->mdata;
501
502	musb_stop(host->host);
503	free(host->host);
504	host->host = NULL;
505
506	return 0;
507}
508
509/*
510 * The Linux driver has a config struct, its fields mapping to this driver
511 * like this:
512 *	.hdrc_config:
513 *		sunxi_musb_hdrc_config_5eps => musb_config
514 *		sunxi_musb_hdrc_config_4eps => musb_config_h3
515 *	.has_sram: always enabled, ideally no-op on SoCs not using it
516 *	.has_reset: automatically detected from DT
517 *	.no_configdata: handled via Kconfig's CONFIG_USB_MUSB_FIXED_CONFIGDATA
518 */
519static const struct sunxi_musb_config sun4i_a10_cfg = {
520	.config = &musb_config,
521};
522
523static const struct sunxi_musb_config sun6i_a31_cfg = {
524	.config = &musb_config,
525};
526
527static const struct sunxi_musb_config sun8i_h3_cfg = {
528	.config = &musb_config_h3,
529};
530
531static const struct sunxi_musb_config suniv_f1c100s_cfg = {
532	.config = &musb_config,
533};
534
535static const struct udevice_id sunxi_musb_ids[] = {
536	{ .compatible = "allwinner,sun4i-a10-musb",
537			.data = (ulong)&sun4i_a10_cfg },
538	{ .compatible = "allwinner,sun6i-a31-musb",
539			.data = (ulong)&sun6i_a31_cfg },
540	{ .compatible = "allwinner,sun8i-a33-musb",
541			.data = (ulong)&sun6i_a31_cfg },
542	{ .compatible = "allwinner,sun8i-h3-musb",
543			.data = (ulong)&sun8i_h3_cfg },
544	{ .compatible = "allwinner,suniv-f1c100s-musb",
545			.data = (ulong)&suniv_f1c100s_cfg },
546	{ }
547};
548
549U_BOOT_DRIVER(usb_musb) = {
550	.name		= "sunxi-musb",
551#ifdef CONFIG_USB_MUSB_HOST
552	.id		= UCLASS_USB,
553#else
554	.id		= UCLASS_USB_GADGET_GENERIC,
555#endif
556	.of_match	= sunxi_musb_ids,
557	.probe		= musb_usb_probe,
558	.remove		= musb_usb_remove,
559#ifdef CONFIG_USB_MUSB_HOST
560	.ops		= &musb_usb_ops,
561#endif
562	.plat_auto	= sizeof(struct usb_plat),
563	.priv_auto	= sizeof(struct sunxi_glue),
564};
565