1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2024-2025, Kongyang Liu <seashell11234455@gmail.com>
4  */
5 
6 #include <linux/bitfield.h>
7 #include <linux/errno.h>
8 #include <linux/io.h>
9 #include <wait_bit.h>
10 
11 #include "dwc2_core.h"
12 
dwc2_core_reset(struct dwc2_core_regs * regs)13 int dwc2_core_reset(struct dwc2_core_regs *regs)
14 {
15 	u32 snpsid;
16 	int ret;
17 	bool host_mode = false;
18 
19 	if (!(readl(&regs->global_regs.gotgctl) & GOTGCTL_CONID_B) ||
20 	    (readl(&regs->global_regs.gusbcfg) & GUSBCFG_FORCEDEVMODE))
21 		host_mode = true;
22 
23 	/* Core Soft Reset */
24 	snpsid = readl(&regs->global_regs.gsnpsid);
25 	writel(GRSTCTL_CSFTRST, &regs->global_regs.grstctl);
26 	if (FIELD_GET(GSNPSID_VER_MASK, snpsid) < 0x420a) {
27 		ret = wait_for_bit_le32(&regs->global_regs.grstctl, GRSTCTL_CSFTRST,
28 					false, 1000, false);
29 		if (ret) {
30 			log_warning("%s: Waiting for GRSTCTL_CSFTRST timeout\n", __func__);
31 			return ret;
32 		}
33 	} else {
34 		ret = wait_for_bit_le32(&regs->global_regs.grstctl, GRSTCTL_CSFTRST_DONE,
35 					true, 1000, false);
36 		if (ret) {
37 			log_warning("%s: Waiting for GRSTCTL_CSFTRST_DONE timeout\n", __func__);
38 			return ret;
39 		}
40 		clrsetbits_le32(&regs->global_regs.grstctl, GRSTCTL_CSFTRST, GRSTCTL_CSFTRST_DONE);
41 	}
42 
43 	/* Wait for AHB master IDLE state. */
44 	ret = wait_for_bit_le32(&regs->global_regs.grstctl, GRSTCTL_AHBIDLE,
45 				true, 1000, false);
46 	if (ret) {
47 		log_warning("%s: Waiting for GRSTCTL_AHBIDLE timeout\n", __func__);
48 		return ret;
49 	}
50 
51 	if (host_mode) {
52 		ret = wait_for_bit_le32(&regs->global_regs.gintsts, GINTSTS_CURMODE_HOST,
53 					host_mode, 1000, false);
54 		if (ret) {
55 			log_warning("%s: Waiting for GINTSTS_CURMODE_HOST timeout\n", __func__);
56 			return ret;
57 		}
58 	}
59 
60 	return 0;
61 }
62 
dwc2_flush_tx_fifo(struct dwc2_core_regs * regs,const int num)63 int dwc2_flush_tx_fifo(struct dwc2_core_regs *regs, const int num)
64 {
65 	int ret;
66 
67 	log_debug("Flush Tx FIFO %d\n", num);
68 
69 	/* Wait for AHB master IDLE state */
70 	ret = wait_for_bit_le32(&regs->global_regs.grstctl, GRSTCTL_AHBIDLE, true, 1000, false);
71 	if (ret) {
72 		log_warning("%s: Waiting for GRSTCTL_AHBIDLE timeout\n", __func__);
73 		return ret;
74 	}
75 
76 	writel(GRSTCTL_TXFFLSH | FIELD_PREP(GRSTCTL_TXFNUM_MASK, num), &regs->global_regs.grstctl);
77 
78 	ret = wait_for_bit_le32(&regs->global_regs.grstctl, GRSTCTL_TXFFLSH, false, 1000, false);
79 	if (ret) {
80 		log_warning("%s: Waiting for GRSTCTL_TXFFLSH timeout\n", __func__);
81 		return ret;
82 	}
83 
84 	/*
85 	 * Wait for at least 3 PHY clocks.
86 	 *
87 	 * The PHY clock frequency can be configured to 6/30/48/60 MHz
88 	 * based on the speed mode. A fixed delay of 1us ensures that the
89 	 * wait time is sufficient even at the lowest PHY clock frequency
90 	 * (6 MHz), where 1us corresponds to twice the duration of 3 PHY
91 	 * clocks.
92 	 */
93 	udelay(1);
94 
95 	return 0;
96 }
97 
dwc2_flush_rx_fifo(struct dwc2_core_regs * regs)98 int dwc2_flush_rx_fifo(struct dwc2_core_regs *regs)
99 {
100 	int ret;
101 
102 	log_debug("Flush Rx FIFO\n");
103 
104 	/* Wait for AHB master IDLE state */
105 	ret = wait_for_bit_le32(&regs->global_regs.grstctl, GRSTCTL_AHBIDLE, true, 1000, false);
106 	if (ret) {
107 		log_warning("%s: Waiting for GRSTCTL_AHBIDLE timeout\n", __func__);
108 		return ret;
109 	}
110 
111 	writel(GRSTCTL_RXFFLSH, &regs->global_regs.grstctl);
112 
113 	ret = wait_for_bit_le32(&regs->global_regs.grstctl, GRSTCTL_RXFFLSH, false, 1000, false);
114 	if (ret) {
115 		log_warning("%s: Waiting for GRSTCTL_RXFFLSH timeout\n", __func__);
116 		return ret;
117 	}
118 
119 	/*
120 	 * Wait for at least 3 PHY clocks.
121 	 *
122 	 * The PHY clock frequency can be configured to 6/30/48/60 MHz
123 	 * based on the speed mode. A fixed delay of 1us ensures that the
124 	 * wait time is sufficient even at the lowest PHY clock frequency
125 	 * (6 MHz), where 1us corresponds to twice the duration of 3 PHY
126 	 * clocks.
127 	 */
128 	udelay(1);
129 
130 	return 0;
131 }
132