1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H
8 #define ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H
9 
10 #include "udc_dwc2.h"
11 
12 #include <stdint.h>
13 #include <zephyr/device.h>
14 #include <zephyr/drivers/usb/udc.h>
15 
16 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg)
17 
18 #include <zephyr/sys/sys_io.h>
19 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
20 #include <usb_dwc2_hw.h>
21 
22 struct usb_dw_stm32_clk {
23 	const struct device *const dev;
24 	const struct stm32_pclken *const pclken;
25 	size_t pclken_len;
26 };
27 
28 #define DT_DRV_COMPAT snps_dwc2
29 
stm32f4_fsotg_enable_clk(const struct usb_dw_stm32_clk * const clk)30 static inline int stm32f4_fsotg_enable_clk(const struct usb_dw_stm32_clk *const clk)
31 {
32 	int ret;
33 
34 	if (!device_is_ready(clk->dev)) {
35 		return -ENODEV;
36 	}
37 
38 	if (clk->pclken_len > 1) {
39 		uint32_t clk_rate;
40 
41 		ret = clock_control_configure(clk->dev,
42 					      (void *)&clk->pclken[1],
43 					      NULL);
44 		if (ret) {
45 			return ret;
46 		}
47 
48 		ret = clock_control_get_rate(clk->dev,
49 					     (void *)&clk->pclken[1],
50 					     &clk_rate);
51 		if (ret) {
52 			return ret;
53 		}
54 
55 		if (clk_rate != MHZ(48)) {
56 			return -ENOTSUP;
57 		}
58 	}
59 
60 	return clock_control_on(clk->dev, (void *)&clk->pclken[0]);
61 }
62 
stm32f4_fsotg_enable_phy(const struct device * dev)63 static inline int stm32f4_fsotg_enable_phy(const struct device *dev)
64 {
65 	const struct udc_dwc2_config *const config = dev->config;
66 	mem_addr_t ggpio_reg = (mem_addr_t)&config->base->ggpio;
67 
68 	sys_set_bits(ggpio_reg, USB_DWC2_GGPIO_STM32_PWRDWN | USB_DWC2_GGPIO_STM32_VBDEN);
69 
70 	return 0;
71 }
72 
stm32f4_fsotg_disable_phy(const struct device * dev)73 static inline int stm32f4_fsotg_disable_phy(const struct device *dev)
74 {
75 	const struct udc_dwc2_config *const config = dev->config;
76 	mem_addr_t ggpio_reg = (mem_addr_t)&config->base->ggpio;
77 
78 	sys_clear_bits(ggpio_reg, USB_DWC2_GGPIO_STM32_PWRDWN | USB_DWC2_GGPIO_STM32_VBDEN);
79 
80 	return 0;
81 }
82 
83 #define QUIRK_STM32F4_FSOTG_DEFINE(n)						\
84 	static const struct stm32_pclken pclken_##n[] = STM32_DT_INST_CLOCKS(n);\
85 										\
86 	static const struct usb_dw_stm32_clk stm32f4_clk_##n = {		\
87 		.dev = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE),			\
88 		.pclken = pclken_##n,						\
89 		.pclken_len = DT_INST_NUM_CLOCKS(n),				\
90 	};									\
91 										\
92 	static int stm32f4_fsotg_enable_clk_##n(const struct device *dev)	\
93 	{									\
94 		return stm32f4_fsotg_enable_clk(&stm32f4_clk_##n);		\
95 	}									\
96 										\
97 	struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = {			\
98 		.pre_enable = stm32f4_fsotg_enable_clk_##n,			\
99 		.post_enable = stm32f4_fsotg_enable_phy,			\
100 		.disable = stm32f4_fsotg_disable_phy,				\
101 		.irq_clear = NULL,						\
102 	};
103 
104 
105 DT_INST_FOREACH_STATUS_OKAY(QUIRK_STM32F4_FSOTG_DEFINE)
106 
107 #undef DT_DRV_COMPAT
108 
109 #endif /*DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg) */
110 
111 #if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs)
112 
113 #define DT_DRV_COMPAT snps_dwc2
114 
115 #include <nrfs_backend_ipc_service.h>
116 #include <nrfs_usb.h>
117 
118 #define USBHS_DT_WRAPPER_REG_ADDR(n) UINT_TO_POINTER(DT_INST_REG_ADDR_BY_NAME(n, wrapper))
119 
120 /*
121  * On USBHS, we cannot access the DWC2 register until VBUS is detected and
122  * valid. If the user tries to force usbd_enable() and the corresponding
123  * udc_enable() without a "VBUS ready" notification, the event wait will block
124  * until a valid VBUS signal is detected or until the
125  * CONFIG_UDC_DWC2_USBHS_VBUS_READY_TIMEOUT timeout expires.
126  */
127 static K_EVENT_DEFINE(usbhs_events);
128 #define USBHS_VBUS_READY	BIT(0)
129 
usbhs_vbus_handler(nrfs_usb_evt_t const * p_evt,void * const context)130 static void usbhs_vbus_handler(nrfs_usb_evt_t const *p_evt, void *const context)
131 {
132 	const struct device *dev = context;
133 
134 	switch (p_evt->type) {
135 	case NRFS_USB_EVT_VBUS_STATUS_CHANGE:
136 		LOG_DBG("USBHS new status, pll_ok = %d vreg_ok = %d vbus_detected = %d",
137 			p_evt->usbhspll_ok, p_evt->vregusb_ok, p_evt->vbus_detected);
138 
139 		if (p_evt->usbhspll_ok && p_evt->vregusb_ok && p_evt->vbus_detected) {
140 			k_event_post(&usbhs_events, USBHS_VBUS_READY);
141 			udc_submit_event(dev, UDC_EVT_VBUS_READY, 0);
142 		} else {
143 			k_event_set_masked(&usbhs_events, 0, USBHS_VBUS_READY);
144 			udc_submit_event(dev, UDC_EVT_VBUS_REMOVED, 0);
145 		}
146 
147 		break;
148 	case NRFS_USB_EVT_REJECT:
149 		LOG_ERR("Request rejected");
150 		break;
151 	default:
152 		LOG_ERR("Unknown event type 0x%x", p_evt->type);
153 		break;
154 	}
155 }
156 
usbhs_enable_nrfs_service(const struct device * dev)157 static inline int usbhs_enable_nrfs_service(const struct device *dev)
158 {
159 	nrfs_err_t nrfs_err;
160 	int err;
161 
162 	err = nrfs_backend_wait_for_connection(K_MSEC(1000));
163 	if (err) {
164 		LOG_INF("NRFS backend connection timeout");
165 		return err;
166 	}
167 
168 	nrfs_err = nrfs_usb_init(usbhs_vbus_handler);
169 	if (nrfs_err != NRFS_SUCCESS) {
170 		LOG_ERR("Failed to init NRFS VBUS handler: %d", nrfs_err);
171 		return -EIO;
172 	}
173 
174 	nrfs_err = nrfs_usb_enable_request((void *)dev);
175 	if (nrfs_err != NRFS_SUCCESS) {
176 		LOG_ERR("Failed to enable NRFS VBUS service: %d", nrfs_err);
177 		return -EIO;
178 	}
179 
180 	return 0;
181 }
182 
usbhs_enable_core(const struct device * dev)183 static inline int usbhs_enable_core(const struct device *dev)
184 {
185 	NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0);
186 	k_timeout_t timeout = K_FOREVER;
187 
188 	#if CONFIG_NRFS_HAS_VBUS_DETECTOR_SERVICE
189 	if (CONFIG_UDC_DWC2_USBHS_VBUS_READY_TIMEOUT) {
190 		timeout = K_MSEC(CONFIG_UDC_DWC2_USBHS_VBUS_READY_TIMEOUT);
191 	}
192 	#endif
193 
194 	if (!k_event_wait(&usbhs_events, USBHS_VBUS_READY, false, K_NO_WAIT)) {
195 		LOG_WRN("VBUS is not ready, block udc_enable()");
196 		if (!k_event_wait(&usbhs_events, USBHS_VBUS_READY, false, timeout)) {
197 			return -ETIMEDOUT;
198 		}
199 	}
200 
201 	wrapper->ENABLE = USBHS_ENABLE_PHY_Msk | USBHS_ENABLE_CORE_Msk;
202 	wrapper->TASKS_START = 1UL;
203 
204 	/* Wait for clock to start to avoid hang on too early register read */
205 	k_busy_wait(1);
206 
207 	/* Enable interrupts */
208 	wrapper->INTENSET = 1UL;
209 
210 	return 0;
211 }
212 
usbhs_disable_core(const struct device * dev)213 static inline int usbhs_disable_core(const struct device *dev)
214 {
215 	NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0);
216 
217 	/* Disable interrupts */
218 	wrapper->INTENCLR = 1UL;
219 
220 	wrapper->ENABLE = 0UL;
221 	wrapper->TASKS_START = 1UL;
222 
223 	return 0;
224 }
225 
usbhs_disable_nrfs_service(const struct device * dev)226 static inline int usbhs_disable_nrfs_service(const struct device *dev)
227 {
228 	nrfs_err_t nrfs_err;
229 
230 	nrfs_err = nrfs_usb_disable_request((void *)dev);
231 	if (nrfs_err != NRFS_SUCCESS) {
232 		LOG_ERR("Failed to disable NRFS VBUS service: %d", nrfs_err);
233 		return -EIO;
234 	}
235 
236 	nrfs_usb_uninit();
237 
238 	return 0;
239 }
240 
usbhs_irq_clear(const struct device * dev)241 static inline int usbhs_irq_clear(const struct device *dev)
242 {
243 	NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0);
244 
245 	wrapper->EVENTS_CORE = 0UL;
246 
247 	return 0;
248 }
249 
usbhs_init_caps(const struct device * dev)250 static inline int usbhs_init_caps(const struct device *dev)
251 {
252 	struct udc_data *data = dev->data;
253 
254 	data->caps.can_detect_vbus = true;
255 	data->caps.hs = true;
256 
257 	return 0;
258 }
259 
usbhs_is_phy_clk_off(const struct device * dev)260 static inline int usbhs_is_phy_clk_off(const struct device *dev)
261 {
262 	return !k_event_test(&usbhs_events, USBHS_VBUS_READY);
263 }
264 
usbhs_post_hibernation_entry(const struct device * dev)265 static inline int usbhs_post_hibernation_entry(const struct device *dev)
266 {
267 	const struct udc_dwc2_config *const config = dev->config;
268 	struct usb_dwc2_reg *const base = config->base;
269 	NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0);
270 
271 	sys_set_bits((mem_addr_t)&base->pcgcctl, USB_DWC2_PCGCCTL_GATEHCLK);
272 
273 	sys_write32(0x87, (mem_addr_t)wrapper + 0xC80);
274 	sys_write32(0x87, (mem_addr_t)wrapper + 0xC84);
275 	sys_write32(1, (mem_addr_t)wrapper + 0x004);
276 
277 	return 0;
278 }
279 
usbhs_pre_hibernation_exit(const struct device * dev)280 static inline int usbhs_pre_hibernation_exit(const struct device *dev)
281 {
282 	const struct udc_dwc2_config *const config = dev->config;
283 	struct usb_dwc2_reg *const base = config->base;
284 	NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0);
285 
286 	sys_clear_bits((mem_addr_t)&base->pcgcctl, USB_DWC2_PCGCCTL_GATEHCLK);
287 
288 	wrapper->TASKS_START = 1;
289 	sys_write32(0, (mem_addr_t)wrapper + 0xC80);
290 	sys_write32(0, (mem_addr_t)wrapper + 0xC84);
291 
292 	return 0;
293 }
294 
295 #define QUIRK_NRF_USBHS_DEFINE(n)						\
296 	struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = {			\
297 		.init = usbhs_enable_nrfs_service,				\
298 		.pre_enable = usbhs_enable_core,				\
299 		.disable = usbhs_disable_core,					\
300 		.shutdown = usbhs_disable_nrfs_service,				\
301 		.irq_clear = usbhs_irq_clear,					\
302 		.caps = usbhs_init_caps,					\
303 		.is_phy_clk_off = usbhs_is_phy_clk_off,				\
304 		.post_hibernation_entry = usbhs_post_hibernation_entry,		\
305 		.pre_hibernation_exit = usbhs_pre_hibernation_exit,		\
306 	};
307 
308 DT_INST_FOREACH_STATUS_OKAY(QUIRK_NRF_USBHS_DEFINE)
309 
310 #undef DT_DRV_COMPAT
311 
312 #endif /*DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs) */
313 
314 /* Add next vendor quirks definition above this line */
315 
316 #endif /* ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H */
317