summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/dwc3-generic-sti.c
blob: b34f5ceceacc2a640ffd82f47145d4da3285949b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
/*
 * STi specific glue layer for DWC3
 *
 * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
 */

#define LOG_CATEGORY UCLASS_NOP

#include <reset.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <dm/device.h>
#include <dm/device_compat.h>
#include <dm/read.h>
#include <linux/usb/otg.h>
#include "dwc3-generic.h"

/* glue registers */
#define CLKRST_CTRL		0x00
#define AUX_CLK_EN		BIT(0)
#define SW_PIPEW_RESET_N	BIT(4)
#define EXT_CFG_RESET_N		BIT(8)

#define XHCI_REVISION		BIT(12)

#define USB2_VBUS_MNGMNT_SEL1	0x2C
#define USB2_VBUS_UTMIOTG	0x1

#define SEL_OVERRIDE_VBUSVALID(n)	((n) << 0)
#define SEL_OVERRIDE_POWERPRESENT(n)	((n) << 4)
#define SEL_OVERRIDE_BVALID(n)		((n) << 8)

/* Static DRD configuration */
#define USB3_CONTROL_MASK		0xf77

#define USB3_DEVICE_NOT_HOST		BIT(0)
#define USB3_FORCE_VBUSVALID		BIT(1)
#define USB3_DELAY_VBUSVALID		BIT(2)
#define USB3_SEL_FORCE_OPMODE		BIT(4)
#define USB3_FORCE_OPMODE(n)		((n) << 5)
#define USB3_SEL_FORCE_DPPULLDOWN2	BIT(8)
#define USB3_FORCE_DPPULLDOWN2		BIT(9)
#define USB3_SEL_FORCE_DMPULLDOWN2	BIT(10)
#define USB3_FORCE_DMPULLDOWN2		BIT(11)

static void dwc3_stih407_glue_configure(struct udevice *dev, int index,
					enum usb_dr_mode mode)
{
	struct dwc3_glue_data *glue = dev_get_plat(dev);
	struct regmap *regmap;
	ulong syscfg_base;
	ulong syscfg_offset;
	ulong glue_base;
	int ret;

	/* deassert both powerdown and softreset */
	ret = reset_deassert_bulk(&glue->resets);
	if (ret) {
		dev_err(dev, "reset_deassert_bulk error: %d\n", ret);
		return;
	}

	regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg");
	if (IS_ERR(regmap)) {
		dev_err(dev, "unable to get st,syscfg, dev %s\n", dev->name);
		return;
	}

	syscfg_base = regmap->ranges[0].start;
	glue_base = dev_read_addr_index(dev, 0);
	syscfg_offset = dev_read_addr_index(dev, 1);

	clrbits_le32(syscfg_base + syscfg_offset, USB3_CONTROL_MASK);

	/* glue drd init */
	switch (mode) {
	case USB_DR_MODE_PERIPHERAL:
		clrbits_le32(syscfg_base + syscfg_offset,
			     USB3_DELAY_VBUSVALID | USB3_SEL_FORCE_OPMODE |
			     USB3_FORCE_OPMODE(0x3) | USB3_SEL_FORCE_DPPULLDOWN2 |
			     USB3_FORCE_DPPULLDOWN2 | USB3_SEL_FORCE_DMPULLDOWN2 |
			     USB3_FORCE_DMPULLDOWN2);

		setbits_le32(syscfg_base + syscfg_offset,
			     USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID);
		break;

	case USB_DR_MODE_HOST:
		clrbits_le32(syscfg_base + syscfg_offset,
			     USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID |
			     USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3) |
			     USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2 |
			     USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);

		setbits_le32(syscfg_base + syscfg_offset, USB3_DELAY_VBUSVALID);
		break;

	default:
		dev_err(dev, "Unsupported mode of operation %d\n", mode);
		return;
	}

	/* glue init */
	setbits_le32(glue_base + CLKRST_CTRL, AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION);
	clrbits_le32(glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N);

	/* configure mux for vbus, powerpresent and bvalid signals */
	setbits_le32(glue_base + USB2_VBUS_MNGMNT_SEL1,
		     SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) |
		     SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) |
		     SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG));
	setbits_le32(glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N);
};

struct dwc3_glue_ops stih407_ops = {
	.glue_configure = dwc3_stih407_glue_configure,
};

static const struct udevice_id dwc3_sti_match[] = {
	{ .compatible = "st,stih407-dwc3", .data = (ulong)&stih407_ops},
	{ /* sentinel */ }
};

U_BOOT_DRIVER(dwc3_sti_wrapper) = {
	.name = "dwc3-sti",
	.id = UCLASS_NOP,
	.of_match = dwc3_sti_match,
	.bind = dwc3_glue_bind,
	.probe = dwc3_glue_probe,
	.remove = dwc3_glue_remove,
	.plat_auto = sizeof(struct dwc3_glue_data),
};