xref: /netbsd-src/sys/arch/arm/nvidia/tegra_xusb.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /* $NetBSD: tegra_xusb.c,v 1.28 2021/08/07 16:18:44 thorpej Exp $ */
285627b23Sjakllsch 
385627b23Sjakllsch /*
485627b23Sjakllsch  * Copyright (c) 2016 Jonathan A. Kollasch
585627b23Sjakllsch  * All rights reserved.
685627b23Sjakllsch  *
785627b23Sjakllsch  * Redistribution and use in source and binary forms, with or without
885627b23Sjakllsch  * modification, are permitted provided that the following conditions
985627b23Sjakllsch  * are met:
1085627b23Sjakllsch  * 1. Redistributions of source code must retain the above copyright
1185627b23Sjakllsch  *    notice, this list of conditions and the following disclaimer.
1285627b23Sjakllsch  * 2. Redistributions in binary form must reproduce the above copyright
1385627b23Sjakllsch  *    notice, this list of conditions and the following disclaimer in the
1485627b23Sjakllsch  *    documentation and/or other materials provided with the distribution.
1585627b23Sjakllsch  *
1685627b23Sjakllsch  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1785627b23Sjakllsch  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1885627b23Sjakllsch  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1985627b23Sjakllsch  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
2085627b23Sjakllsch  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2185627b23Sjakllsch  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2285627b23Sjakllsch  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2385627b23Sjakllsch  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2485627b23Sjakllsch  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2585627b23Sjakllsch  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2685627b23Sjakllsch  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2785627b23Sjakllsch  */
2885627b23Sjakllsch 
2985627b23Sjakllsch #include "locators.h"
3085627b23Sjakllsch #include "opt_tegra.h"
3185627b23Sjakllsch 
3285627b23Sjakllsch #include <sys/cdefs.h>
33*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: tegra_xusb.c,v 1.28 2021/08/07 16:18:44 thorpej Exp $");
3485627b23Sjakllsch 
3585627b23Sjakllsch #include <sys/param.h>
3685627b23Sjakllsch #include <sys/bus.h>
3785627b23Sjakllsch #include <sys/device.h>
3885627b23Sjakllsch #include <sys/intr.h>
3985627b23Sjakllsch #include <sys/systm.h>
4085627b23Sjakllsch #include <sys/kernel.h>
4185627b23Sjakllsch 
4285627b23Sjakllsch #include <arm/nvidia/tegra_reg.h>
4385627b23Sjakllsch #include <arm/nvidia/tegra_var.h>
44a7c423b9Sjmcneill #include <arm/nvidia/tegra_xusbpad.h>
4585627b23Sjakllsch #include <arm/nvidia/tegra_xusbreg.h>
4632f88b93Sjmcneill #include <arm/nvidia/tegra_pmcreg.h>
4732f88b93Sjmcneill 
4885627b23Sjakllsch #include <dev/pci/pcireg.h>
4985627b23Sjakllsch 
5085627b23Sjakllsch #include <dev/fdt/fdtvar.h>
5185627b23Sjakllsch 
5285627b23Sjakllsch #include <dev/firmload.h>
5385627b23Sjakllsch 
5485627b23Sjakllsch #include <dev/usb/usb.h>
5585627b23Sjakllsch #include <dev/usb/usbdi.h>
5685627b23Sjakllsch #include <dev/usb/usbdivar.h>
5785627b23Sjakllsch #include <dev/usb/usb_mem.h>
5885627b23Sjakllsch 
5985627b23Sjakllsch #include <dev/usb/xhcireg.h>
6085627b23Sjakllsch #include <dev/usb/xhcivar.h>
6185627b23Sjakllsch 
6267b89dbeSjmcneill #ifdef TEGRA_XUSB_DEBUG
6367b89dbeSjmcneill int tegra_xusb_debug = 1;
6467b89dbeSjmcneill #else
6567b89dbeSjmcneill int tegra_xusb_debug = 0;
6667b89dbeSjmcneill #endif
6767b89dbeSjmcneill 
6867b89dbeSjmcneill #define DPRINTF(...)	if (tegra_xusb_debug) device_printf(__VA_ARGS__)
6967b89dbeSjmcneill 
7085627b23Sjakllsch static int	tegra_xusb_match(device_t, cfdata_t, void *);
7185627b23Sjakllsch static void	tegra_xusb_attach(device_t, device_t, void *);
7285627b23Sjakllsch static void	tegra_xusb_mountroot(device_t);
7385627b23Sjakllsch 
7485627b23Sjakllsch static int	tegra_xusb_intr_mbox(void *);
7585627b23Sjakllsch 
7685627b23Sjakllsch #ifdef TEGRA124_XUSB_BIN_STATIC
7785627b23Sjakllsch extern const char _binary_tegra124_xusb_bin_start[];
785ea5576aSjakllsch extern const char _binary_tegra124_xusb_bin_end[];
795ea5576aSjakllsch __asm__(
805ea5576aSjakllsch ".section \".rodata\"\n"
815ea5576aSjakllsch "_binary_tegra124_xusb_bin_start:\n"
825ea5576aSjakllsch ".incbin \"../external/nvidia-firmware/tegra/dist/tegra124/xusb.bin\"\n"
835ea5576aSjakllsch ".size _binary_tegra124_xusb_bin_start, . - _binary_tegra124_xusb_bin_start\n"
845ea5576aSjakllsch "_binary_tegra124_xusb_bin_end:\n"
855ea5576aSjakllsch ".previous\n"
865ea5576aSjakllsch );
8785627b23Sjakllsch #endif
8885627b23Sjakllsch 
89a7c423b9Sjmcneill #ifdef TEGRA210_XUSB_BIN_STATIC
90a7c423b9Sjmcneill extern const char _binary_tegra210_xusb_bin_start[];
915ea5576aSjakllsch extern const char _binary_tegra210_xusb_bin_end[];
925ea5576aSjakllsch __asm__(
935ea5576aSjakllsch ".section \".rodata\"\n"
945ea5576aSjakllsch "_binary_tegra210_xusb_bin_start:\n"
955ea5576aSjakllsch ".incbin \"../external/nvidia-firmware/tegra/dist/tegra210/xusb.bin\"\n"
965ea5576aSjakllsch ".size _binary_tegra210_xusb_bin_start, . - _binary_tegra210_xusb_bin_start\n"
975ea5576aSjakllsch "_binary_tegra210_xusb_bin_end:\n"
985ea5576aSjakllsch ".previous\n"
995ea5576aSjakllsch );
100a7c423b9Sjmcneill #endif
101a7c423b9Sjmcneill 
102a7c423b9Sjmcneill enum xusb_type {
103a7c423b9Sjmcneill 	XUSB_T124 = 1,
104a7c423b9Sjmcneill 	XUSB_T210
105a7c423b9Sjmcneill };
106a7c423b9Sjmcneill 
107055a5e80Sskrll struct tegra_xhci_data {
108055a5e80Sskrll 	enum xusb_type		txd_type;
109055a5e80Sskrll 	const char * const *	txd_supplies;
110055a5e80Sskrll 	size_t			txd_nsupplies;
111055a5e80Sskrll 	bool			txd_scale_ss_clock;
112055a5e80Sskrll };
113055a5e80Sskrll 
114055a5e80Sskrll const char *tegra124_xhci_supplies[] = {
115055a5e80Sskrll 	"dvddio-pex-supply",
116055a5e80Sskrll 	"hvddio-pex-supply",
117055a5e80Sskrll 	"avdd-usb-supply",
118055a5e80Sskrll 	"avdd-pll-utmip-supply",
119055a5e80Sskrll 	"avdd-pll-uerefe-supply",
120055a5e80Sskrll 	"dvdd-usb-ss-pll-supply",
121055a5e80Sskrll 	"hvdd-usb-ss-pll-e-supply"
122055a5e80Sskrll };
123055a5e80Sskrll 
124055a5e80Sskrll struct tegra_xhci_data tegra124_xhci_data = {
125055a5e80Sskrll 	.txd_type = XUSB_T124,
126055a5e80Sskrll 	.txd_supplies = tegra124_xhci_supplies,
127055a5e80Sskrll 	.txd_nsupplies = __arraycount(tegra124_xhci_supplies),
128055a5e80Sskrll 	.txd_scale_ss_clock = true,
129055a5e80Sskrll };
130055a5e80Sskrll 
131055a5e80Sskrll const char *tegra210_xhci_supplies[] = {
132055a5e80Sskrll 	"dvddio-pex",
133055a5e80Sskrll 	"hvddio-pex",
134055a5e80Sskrll 	"avdd-usb",
135055a5e80Sskrll 	"avdd-pll-utmip",
136055a5e80Sskrll 	"avdd-pll-uerefe",
137055a5e80Sskrll 	"dvdd-pex-pll",
138055a5e80Sskrll 	"hvdd-pex-pll-e",
139055a5e80Sskrll };
140055a5e80Sskrll 
141055a5e80Sskrll struct tegra_xhci_data tegra210_xhci_data = {
142055a5e80Sskrll 	.txd_type = XUSB_T210,
143055a5e80Sskrll 	.txd_supplies = tegra210_xhci_supplies,
144055a5e80Sskrll 	.txd_nsupplies = __arraycount(tegra210_xhci_supplies),
145055a5e80Sskrll 	.txd_scale_ss_clock = false,
146055a5e80Sskrll };
147055a5e80Sskrll 
148646c0f59Sthorpej static const struct device_compatible_entry compat_data[] = {
149646c0f59Sthorpej 	{ .compat = "nvidia,tegra124-xusb", .data = &tegra124_xhci_data },
150646c0f59Sthorpej 	{ .compat = "nvidia,tegra210-xusb", .data = &tegra210_xhci_data },
151ec189949Sthorpej 	DEVICE_COMPAT_EOL
152a7c423b9Sjmcneill };
153a7c423b9Sjmcneill 
15485627b23Sjakllsch struct fw_dma {
15585627b23Sjakllsch 	bus_dmamap_t            map;
15685627b23Sjakllsch 	void *                  addr;
15785627b23Sjakllsch 	bus_dma_segment_t       segs[1];
15885627b23Sjakllsch 	int                     nsegs;
15985627b23Sjakllsch 	size_t                  size;
16085627b23Sjakllsch };
16185627b23Sjakllsch 
16285627b23Sjakllsch struct tegra_xusb_softc {
16385627b23Sjakllsch 	struct xhci_softc	sc_xhci;
16485627b23Sjakllsch 	int			sc_phandle;
16585627b23Sjakllsch 	bus_space_handle_t	sc_bsh_xhci;
16685627b23Sjakllsch 	bus_space_handle_t	sc_bsh_fpci;
16785627b23Sjakllsch 	bus_space_handle_t	sc_bsh_ipfs;
16885627b23Sjakllsch 	void			*sc_ih;
16985627b23Sjakllsch 	void			*sc_ih_mbox;
17085627b23Sjakllsch 	struct fw_dma		sc_fw_dma;
17185627b23Sjakllsch 	struct clk		*sc_clk_ss_src;
17257030377Sjmcneill 
173646c0f59Sthorpej 	const struct tegra_xhci_data *sc_txd;
17485627b23Sjakllsch };
17585627b23Sjakllsch 
17685627b23Sjakllsch static uint32_t	csb_read_4(struct tegra_xusb_softc * const, bus_size_t);
17785627b23Sjakllsch static void	csb_write_4(struct tegra_xusb_softc * const, bus_size_t,
17885627b23Sjakllsch     uint32_t);
17985627b23Sjakllsch 
18085627b23Sjakllsch static void	tegra_xusb_init(struct tegra_xusb_softc * const);
181a7c423b9Sjmcneill static int	tegra_xusb_open_fw(struct tegra_xusb_softc * const);
182a7c423b9Sjmcneill static int	tegra_xusb_load_fw(struct tegra_xusb_softc * const, void *,
183a7c423b9Sjmcneill     size_t);
18469339524Sjmcneill static void	tegra_xusb_init_regulators(struct tegra_xusb_softc * const);
18585627b23Sjakllsch 
18685627b23Sjakllsch static int	xusb_mailbox_send(struct tegra_xusb_softc * const, uint32_t);
18785627b23Sjakllsch 
18885627b23Sjakllsch CFATTACH_DECL_NEW(tegra_xusb, sizeof(struct tegra_xusb_softc),
18985627b23Sjakllsch 	tegra_xusb_match, tegra_xusb_attach, NULL, NULL);
19085627b23Sjakllsch 
19185627b23Sjakllsch static int
tegra_xusb_match(device_t parent,cfdata_t cf,void * aux)19285627b23Sjakllsch tegra_xusb_match(device_t parent, cfdata_t cf, void *aux)
19385627b23Sjakllsch {
19485627b23Sjakllsch 	struct fdt_attach_args * const faa = aux;
19585627b23Sjakllsch 
1966e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
19785627b23Sjakllsch }
19885627b23Sjakllsch 
19904475725Sskrll #define tegra_xusb_attach_check(sc, cond, fmt, ...)			\
20004475725Sskrll     do {								\
20104475725Sskrll 	if (cond) {							\
20204475725Sskrll 		aprint_error_dev(sc->sc_dev, fmt, ## __VA_ARGS__);	\
20304475725Sskrll 		return;							\
20404475725Sskrll 	}								\
20504475725Sskrll     } while (0)
20604475725Sskrll 
20785627b23Sjakllsch static void
tegra_xusb_attach(device_t parent,device_t self,void * aux)20885627b23Sjakllsch tegra_xusb_attach(device_t parent, device_t self, void *aux)
20985627b23Sjakllsch {
21085627b23Sjakllsch 	struct tegra_xusb_softc * const psc = device_private(self);
21185627b23Sjakllsch 	struct xhci_softc * const sc = &psc->sc_xhci;
21285627b23Sjakllsch 	struct fdt_attach_args * const faa = aux;
213a7c423b9Sjmcneill 	bool wait_for_root = true;
21485627b23Sjakllsch 	char intrstr[128];
21585627b23Sjakllsch 	bus_addr_t addr;
21685627b23Sjakllsch 	bus_size_t size;
21767b89dbeSjmcneill 	struct fdtbus_reset *rst;
218479a90aaSjmcneill 	struct fdtbus_phy *phy;
21985627b23Sjakllsch 	struct clk *clk;
22085627b23Sjakllsch 	uint32_t rate;
221479a90aaSjmcneill 	int error, n;
22285627b23Sjakllsch 
22385627b23Sjakllsch 	aprint_naive("\n");
22485627b23Sjakllsch 	aprint_normal(": XUSB\n");
22585627b23Sjakllsch 
22685627b23Sjakllsch 	sc->sc_dev = self;
22785627b23Sjakllsch 	sc->sc_iot = faa->faa_bst;
22885627b23Sjakllsch 	sc->sc_bus.ub_hcpriv = sc;
22985627b23Sjakllsch 	sc->sc_bus.ub_dmatag = faa->faa_dmat;
23057030377Sjmcneill 	sc->sc_quirks = XHCI_DEFERRED_START;
23185627b23Sjakllsch 	psc->sc_phandle = faa->faa_phandle;
23285627b23Sjakllsch 
2336e54367aSthorpej 	psc->sc_txd = of_compatible_lookup(faa->faa_phandle, compat_data)->data;
23457030377Sjmcneill 
23557030377Sjmcneill 	if (fdtbus_get_reg_byname(faa->faa_phandle, "hcd", &addr, &size) != 0) {
23685627b23Sjakllsch 		aprint_error(": couldn't get registers\n");
23785627b23Sjakllsch 		return;
23885627b23Sjakllsch 	}
23985627b23Sjakllsch 	error = bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh);
24085627b23Sjakllsch 	if (error) {
2412e65b46dSskrll 		aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", addr, error);
24285627b23Sjakllsch 		return;
24385627b23Sjakllsch 	}
244b815897eSskrll 	DPRINTF(sc->sc_dev, "mapped %#" PRIxBUSADDR "\n", addr);
24514ea18b1Sjmcneill 	sc->sc_ios = size;
24685627b23Sjakllsch 
24757030377Sjmcneill 	if (fdtbus_get_reg_byname(faa->faa_phandle, "fpci", &addr, &size) != 0) {
24885627b23Sjakllsch 		aprint_error(": couldn't get registers\n");
24985627b23Sjakllsch 		return;
25085627b23Sjakllsch 	}
25185627b23Sjakllsch 	error = bus_space_map(sc->sc_iot, addr, size, 0, &psc->sc_bsh_fpci);
25285627b23Sjakllsch 	if (error) {
2532e65b46dSskrll 		aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", addr, error);
25485627b23Sjakllsch 		return;
25585627b23Sjakllsch 	}
256b815897eSskrll 	DPRINTF(sc->sc_dev, "mapped %#" PRIxBUSADDR "\n", addr);
25785627b23Sjakllsch 
25857030377Sjmcneill 	if (fdtbus_get_reg_byname(faa->faa_phandle, "ipfs", &addr, &size) != 0) {
25985627b23Sjakllsch 		aprint_error(": couldn't get registers\n");
26085627b23Sjakllsch 		return;
26185627b23Sjakllsch 	}
26285627b23Sjakllsch 	error = bus_space_map(sc->sc_iot, addr, size, 0, &psc->sc_bsh_ipfs);
26385627b23Sjakllsch 	if (error) {
2642e65b46dSskrll 		aprint_error(": couldn't map %#" PRIxBUSADDR ": %d", addr, error);
26585627b23Sjakllsch 		return;
26685627b23Sjakllsch 	}
267b815897eSskrll 	DPRINTF(sc->sc_dev, "mapped %#" PRIxBUSADDR "\n", addr);
26885627b23Sjakllsch 
26985627b23Sjakllsch 	if (!fdtbus_intr_str(faa->faa_phandle, 0, intrstr, sizeof(intrstr))) {
27085627b23Sjakllsch 		aprint_error_dev(self, "failed to decode interrupt\n");
27185627b23Sjakllsch 		return;
27285627b23Sjakllsch 	}
27385627b23Sjakllsch 
2743f513eddSjmcneill 	psc->sc_ih = fdtbus_intr_establish_xname(faa->faa_phandle, 0, IPL_USB,
2753f513eddSjmcneill 	    FDT_INTR_MPSAFE, xhci_intr, sc, device_xname(self));
27685627b23Sjakllsch 	if (psc->sc_ih == NULL) {
27785627b23Sjakllsch 		aprint_error_dev(self, "failed to establish interrupt on %s\n",
27885627b23Sjakllsch 		    intrstr);
27985627b23Sjakllsch 		return;
28085627b23Sjakllsch 	}
28185627b23Sjakllsch 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
28285627b23Sjakllsch 
28385627b23Sjakllsch 	if (!fdtbus_intr_str(faa->faa_phandle, 1, intrstr, sizeof(intrstr))) {
28485627b23Sjakllsch 		aprint_error_dev(self, "failed to decode interrupt\n");
28585627b23Sjakllsch 		return;
28685627b23Sjakllsch 	}
28785627b23Sjakllsch 
2883f513eddSjmcneill 	psc->sc_ih_mbox = fdtbus_intr_establish_xname(faa->faa_phandle, 1,
2893f513eddSjmcneill 	    IPL_VM, FDT_INTR_MPSAFE, tegra_xusb_intr_mbox, psc,
2903f513eddSjmcneill 	    device_xname(self));
29185627b23Sjakllsch 	if (psc->sc_ih_mbox == NULL) {
29285627b23Sjakllsch 		aprint_error_dev(self, "failed to establish interrupt on %s\n",
29385627b23Sjakllsch 		    intrstr);
29485627b23Sjakllsch 		return;
29585627b23Sjakllsch 	}
29685627b23Sjakllsch 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
29785627b23Sjakllsch 
298479a90aaSjmcneill 	/* Enable PHYs */
299479a90aaSjmcneill 	for (n = 0; (phy = fdtbus_phy_get_index(faa->faa_phandle, n)) != NULL; n++)
300479a90aaSjmcneill 		if (fdtbus_phy_enable(phy, true) != 0)
301479a90aaSjmcneill 			aprint_error_dev(self, "failed to enable PHY #%d\n", n);
302479a90aaSjmcneill 
30332f88b93Sjmcneill 	/* Enable XUSB power rails */
30432f88b93Sjmcneill 
30532f88b93Sjmcneill 	tegra_pmc_power(PMC_PARTID_XUSBC, true);	/* Host/USB2.0 */
306479a90aaSjmcneill 	tegra_pmc_remove_clamping(PMC_PARTID_XUSBC);
30732f88b93Sjmcneill 	tegra_pmc_power(PMC_PARTID_XUSBA, true);	/* SuperSpeed */
308479a90aaSjmcneill 	tegra_pmc_remove_clamping(PMC_PARTID_XUSBA);
30932f88b93Sjmcneill 
31032f88b93Sjmcneill 	/* Enable XUSB clocks */
31132f88b93Sjmcneill 
31285627b23Sjakllsch 	clk = fdtbus_clock_get(faa->faa_phandle, "pll_e");
31385627b23Sjakllsch 	rate = clk_get_rate(clk);
31485627b23Sjakllsch 	error = clk_enable(clk); /* XXX set frequency */
31567b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
31604475725Sskrll 	tegra_xusb_attach_check(sc, error, "failed to enable pll_e clock");
31785627b23Sjakllsch 
31885627b23Sjakllsch 	clk = fdtbus_clock_get(faa->faa_phandle, "xusb_host_src");
31985627b23Sjakllsch 	rate = clk_get_rate(clk);
32067b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
32185627b23Sjakllsch 	error = clk_set_rate(clk, 102000000);
32204475725Sskrll 	tegra_xusb_attach_check(sc, error, "failed to set xusb_host_src clock rate");
32304475725Sskrll 
32485627b23Sjakllsch 	rate = clk_get_rate(clk);
32585627b23Sjakllsch 	error = clk_enable(clk); /* XXX set frequency */
32667b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
32704475725Sskrll 	tegra_xusb_attach_check(sc, error, "failed to enable xusb_host_src clock");
32885627b23Sjakllsch 
32985627b23Sjakllsch 	clk = fdtbus_clock_get(faa->faa_phandle, "xusb_falcon_src");
33085627b23Sjakllsch 	rate = clk_get_rate(clk);
33167b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
33285627b23Sjakllsch 	error = clk_set_rate(clk, 204000000);
33304475725Sskrll 	tegra_xusb_attach_check(sc, error, "failed to set xusb_falcon_src clock rate");
33404475725Sskrll 
33585627b23Sjakllsch 	rate = clk_get_rate(clk);
33685627b23Sjakllsch 	error = clk_enable(clk);
33767b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
33804475725Sskrll 	tegra_xusb_attach_check(sc, error, "failed to enable xusb_falcon_src clock");
33985627b23Sjakllsch 
34085627b23Sjakllsch 	clk = fdtbus_clock_get(faa->faa_phandle, "xusb_host");
34185627b23Sjakllsch 	rate = clk_get_rate(clk);
34285627b23Sjakllsch 	error = clk_enable(clk); /* XXX set frequency */
34367b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
34485627b23Sjakllsch 
34585627b23Sjakllsch 	clk = fdtbus_clock_get(faa->faa_phandle, "xusb_ss");
34685627b23Sjakllsch 	rate = clk_get_rate(clk);
34785627b23Sjakllsch 	error = clk_enable(clk); /* XXX set frequency */
34867b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "xusb_ss rate %u error %d\n", rate, error);
34904475725Sskrll 	tegra_xusb_attach_check(sc, error, "failed to enable xusb_ss clock");
35085627b23Sjakllsch 
35185627b23Sjakllsch 	psc->sc_clk_ss_src = fdtbus_clock_get(faa->faa_phandle, "xusb_ss_src");
35204475725Sskrll 	tegra_xusb_attach_check(sc, psc->sc_clk_ss_src == NULL,
35304475725Sskrll 		"failed to get xusb_ss_src clock");
354e69bfca1Sjmcneill 
355055a5e80Sskrll 	if (psc->sc_txd->txd_scale_ss_clock) {
35685627b23Sjakllsch 		rate = clk_get_rate(psc->sc_clk_ss_src);
35767b89dbeSjmcneill 		DPRINTF(sc->sc_dev, "xusb_ss_src rate %u\n", rate);
35885627b23Sjakllsch 		error = clk_set_rate(psc->sc_clk_ss_src, 2000000);
35985627b23Sjakllsch 		rate = clk_get_rate(psc->sc_clk_ss_src);
36067b89dbeSjmcneill 		DPRINTF(sc->sc_dev, "xusb_ss_src rate %u error %d\n", rate, error);
36104475725Sskrll 		tegra_xusb_attach_check(sc, error, "failed to get xusb_ss_src clock rate");
36285627b23Sjakllsch 
36385627b23Sjakllsch 		rate = clk_get_rate(psc->sc_clk_ss_src);
36467b89dbeSjmcneill 		DPRINTF(sc->sc_dev, "ss_src rate %u\n", rate);
36504475725Sskrll 		tegra_xusb_attach_check(sc, error, "failed to set xusb_ss_src clock rate");
36685627b23Sjakllsch 
36785627b23Sjakllsch 		error = clk_set_rate(psc->sc_clk_ss_src, 120000000);
36885627b23Sjakllsch 		rate = clk_get_rate(psc->sc_clk_ss_src);
36967b89dbeSjmcneill 		DPRINTF(sc->sc_dev, "ss_src rate %u error %d\n", rate, error);
37004475725Sskrll 		tegra_xusb_attach_check(sc, error, "failed to get xusb_ss_src clock rate");
371a7c423b9Sjmcneill 	}
37285627b23Sjakllsch 
373a7c423b9Sjmcneill 	rate = clk_get_rate(psc->sc_clk_ss_src);
37485627b23Sjakllsch 	error = clk_enable(psc->sc_clk_ss_src);
37567b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "ss_src rate %u error %d\n", rate, error);
37604475725Sskrll 	tegra_xusb_attach_check(sc, error, "failed to enable xusb_ss_src clock");
37785627b23Sjakllsch 
37885627b23Sjakllsch #if 0
37985627b23Sjakllsch 	clk = fdtbus_clock_get(faa->faa_phandle, "xusb_hs_src");
38085627b23Sjakllsch 	error = 0;
38185627b23Sjakllsch 	rate = clk_get_rate(clk);
38267b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
38385627b23Sjakllsch #endif
38485627b23Sjakllsch 
38585627b23Sjakllsch 	clk = fdtbus_clock_get(faa->faa_phandle, "xusb_fs_src");
38685627b23Sjakllsch 	rate = clk_get_rate(clk);
38785627b23Sjakllsch 	error = clk_enable(clk); /* XXX set frequency */
38867b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
38904475725Sskrll 	tegra_xusb_attach_check(sc, error, "failed to enable xusb_fs_src clock");
39085627b23Sjakllsch 
39185627b23Sjakllsch 	rst = fdtbus_reset_get(faa->faa_phandle, "xusb_host");
39285627b23Sjakllsch 	fdtbus_reset_deassert(rst);
39385627b23Sjakllsch 
39485627b23Sjakllsch 	rst = fdtbus_reset_get(faa->faa_phandle, "xusb_src");
39585627b23Sjakllsch 	fdtbus_reset_deassert(rst);
39685627b23Sjakllsch 
39785627b23Sjakllsch 	rst = fdtbus_reset_get(faa->faa_phandle, "xusb_ss");
39885627b23Sjakllsch 	fdtbus_reset_deassert(rst);
39985627b23Sjakllsch 
40085627b23Sjakllsch 	DELAY(1);
40185627b23Sjakllsch 
40269339524Sjmcneill 	tegra_xusb_init_regulators(psc);
40369339524Sjmcneill 
40485627b23Sjakllsch 	tegra_xusb_init(psc);
40585627b23Sjakllsch 
40685627b23Sjakllsch #if defined(TEGRA124_XUSB_BIN_STATIC)
407055a5e80Sskrll 	if (psc->sc_txd->txd_type == XUSB_T124)
408a7c423b9Sjmcneill 		wait_for_root = false;
40985627b23Sjakllsch #endif
410a7c423b9Sjmcneill #if defined(TEGRA210_XUSB_BIN_STATIC)
411055a5e80Sskrll 	if (psc->sc_txd->txd_type == XUSB_T210)
412a7c423b9Sjmcneill 		wait_for_root = false;
413a7c423b9Sjmcneill #endif
414a7c423b9Sjmcneill 
415a7c423b9Sjmcneill 	if (wait_for_root)
416a7c423b9Sjmcneill 		config_mountroot(sc->sc_dev, tegra_xusb_mountroot);
417a7c423b9Sjmcneill 	else
418a7c423b9Sjmcneill 		tegra_xusb_mountroot(sc->sc_dev);
41985627b23Sjakllsch }
42085627b23Sjakllsch 
42185627b23Sjakllsch static void
tegra_xusb_mountroot(device_t self)42285627b23Sjakllsch tegra_xusb_mountroot(device_t self)
42385627b23Sjakllsch {
42485627b23Sjakllsch 	struct tegra_xusb_softc * const psc = device_private(self);
42585627b23Sjakllsch 	struct xhci_softc * const sc = &psc->sc_xhci;
42685627b23Sjakllsch 	const bus_space_tag_t bst = sc->sc_iot;
42785627b23Sjakllsch 	const bus_space_handle_t ipfsh = psc->sc_bsh_ipfs;
42885627b23Sjakllsch 	struct clk *clk;
42985627b23Sjakllsch 	struct fdtbus_reset *rst;
43085627b23Sjakllsch 	uint32_t rate;
43185627b23Sjakllsch 	uint32_t val;
43285627b23Sjakllsch 	int error;
43385627b23Sjakllsch 
43467b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s()\n", __func__);
43585627b23Sjakllsch 
43685627b23Sjakllsch 	val = bus_space_read_4(bst, ipfsh, 0x0);
43767b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x0 = 0x%x\n", __func__, val);
43885627b23Sjakllsch 
439a7c423b9Sjmcneill 	if (tegra_xusb_open_fw(psc) != 0)
440030df658Sjmcneill 		return;
44167b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "post fw\n");
44285627b23Sjakllsch 
443030df658Sjmcneill 	tegra_xusbpad_xhci_enable();
444030df658Sjmcneill 
44585627b23Sjakllsch 	clk = fdtbus_clock_get(psc->sc_phandle, "xusb_falcon_src");
44685627b23Sjakllsch 	rate = clk_get_rate(clk);
44785627b23Sjakllsch 	error = clk_enable(clk);
44867b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
44985627b23Sjakllsch 
45085627b23Sjakllsch 	clk = fdtbus_clock_get(psc->sc_phandle, "xusb_host_src");
45185627b23Sjakllsch 	rate = clk_get_rate(clk);
45285627b23Sjakllsch 	error = clk_enable(clk);
45367b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "rate %u error %d\n", rate, error);
45485627b23Sjakllsch 
45585627b23Sjakllsch 	val = bus_space_read_4(bst, ipfsh, 0x0);
45667b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x0 = 0x%x\n", __func__, val);
45785627b23Sjakllsch 
45885627b23Sjakllsch 	rst = fdtbus_reset_get(psc->sc_phandle, "xusb_host");
45985627b23Sjakllsch 	fdtbus_reset_deassert(rst);
46085627b23Sjakllsch 
46185627b23Sjakllsch 	rst = fdtbus_reset_get(psc->sc_phandle, "xusb_src");
46285627b23Sjakllsch 	fdtbus_reset_deassert(rst);
46385627b23Sjakllsch 
46485627b23Sjakllsch 	rst = fdtbus_reset_get(psc->sc_phandle, "xusb_ss");
46585627b23Sjakllsch 	fdtbus_reset_deassert(rst);
46685627b23Sjakllsch 
46785627b23Sjakllsch 	val = csb_read_4(psc, XUSB_CSB_FALCON_CPUCTL_REG);
46867b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_CPUCTL 0x%x\n", val);
46985627b23Sjakllsch 
470cd131a63Smsaitoh 	val = bus_space_read_4(bst, psc->sc_bsh_fpci, PCI_USBREV)
471cd131a63Smsaitoh 	    & PCI_USBREV_MASK;
472cd131a63Smsaitoh 	switch (val) {
473cd131a63Smsaitoh 	case PCI_USBREV_3_0:
474cd131a63Smsaitoh 		sc->sc_bus.ub_revision = USBREV_3_0;
475cd131a63Smsaitoh 		break;
476cd131a63Smsaitoh 	case PCI_USBREV_3_1:
477cd131a63Smsaitoh 		sc->sc_bus.ub_revision = USBREV_3_1;
478cd131a63Smsaitoh 		break;
479cd131a63Smsaitoh 	default:
480cd131a63Smsaitoh 		if (val < PCI_USBREV_3_0) {
481a5d63f15Sjmcneill 			aprint_error_dev(self, "Unknown revision (%02x)\n", val);
482cd131a63Smsaitoh 			sc->sc_bus.ub_revision = USBREV_UNKNOWN;
483cd131a63Smsaitoh 		} else {
484cd131a63Smsaitoh 			/* Default to the latest revision */
485cd131a63Smsaitoh 			aprint_normal_dev(self,
486a5d63f15Sjmcneill 			    "Unknown revision (%02x). Set to 3.1.\n", val);
487cd131a63Smsaitoh 			sc->sc_bus.ub_revision = USBREV_3_1;
488cd131a63Smsaitoh 		}
489cd131a63Smsaitoh 		break;
490cd131a63Smsaitoh 	}
491cd131a63Smsaitoh 
49285627b23Sjakllsch 	error = xhci_init(sc);
49385627b23Sjakllsch 	if (error) {
49485627b23Sjakllsch 		aprint_error_dev(self, "init failed, error=%d\n", error);
49585627b23Sjakllsch 		return;
49685627b23Sjakllsch 	}
49785627b23Sjakllsch 
498*c7fb772bSthorpej 	sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint, CFARGS_NONE);
49985627b23Sjakllsch 
5002685996bSthorpej 	sc->sc_child2 = config_found(self, &sc->sc_bus2, usbctlprint,
501*c7fb772bSthorpej 	    CFARGS_NONE);
502a3e10f0dSskrll 
50357030377Sjmcneill 	xhci_start(sc);
50457030377Sjmcneill 
50585627b23Sjakllsch 	error = xusb_mailbox_send(psc, 0x01000000);
50685627b23Sjakllsch 	if (error) {
50785627b23Sjakllsch 		aprint_error_dev(self, "send failed, error=%d\n", error);
50885627b23Sjakllsch 	}
50985627b23Sjakllsch }
51085627b23Sjakllsch 
51185627b23Sjakllsch static int
tegra_xusb_intr_mbox(void * v)51285627b23Sjakllsch tegra_xusb_intr_mbox(void *v)
51385627b23Sjakllsch {
51485627b23Sjakllsch 	struct tegra_xusb_softc * const psc = v;
51585627b23Sjakllsch 	struct xhci_softc * const sc = &psc->sc_xhci;
51685627b23Sjakllsch 	const bus_space_tag_t bst = sc->sc_iot;
51785627b23Sjakllsch 	const bus_space_handle_t fpcih = psc->sc_bsh_fpci;
51885627b23Sjakllsch 	uint32_t val;
51985627b23Sjakllsch 	uint32_t irv;
52085627b23Sjakllsch 	uint32_t msg;
52185627b23Sjakllsch 	int error;
52285627b23Sjakllsch 
52367b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s()\n", __func__);
52485627b23Sjakllsch 
52585627b23Sjakllsch 	irv = bus_space_read_4(bst, fpcih, T_XUSB_CFG_ARU_SMI_INTR_REG);
52667b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CFG_ARU_SMI_INTR 0x%x\n", irv);
52785627b23Sjakllsch 	bus_space_write_4(bst, fpcih, T_XUSB_CFG_ARU_SMI_INTR_REG, irv);
52885627b23Sjakllsch 
52985627b23Sjakllsch 	if (irv & T_XUSB_CFG_ARU_SMI_INTR_FW_HANG)
53067b89dbeSjmcneill 		aprint_error_dev(sc->sc_dev, "firmware hang\n");
53185627b23Sjakllsch 
53285627b23Sjakllsch 	msg = bus_space_read_4(bst, fpcih, T_XUSB_CFG_ARU_MAILBOX_DATA_OUT_REG);
53367b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CFG_ARU_MBOX_DATA_OUT 0x%x\n", msg);
53485627b23Sjakllsch 
53585627b23Sjakllsch 	val = bus_space_read_4(bst, fpcih, T_XUSB_CFG_ARU_MAILBOX_CMD_REG);
53667b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CFG_ARU_MBOX_CMD 0x%x\n", val);
53785627b23Sjakllsch 	val &= ~T_XUSB_CFG_ARU_MAILBOX_CMD_DEST_SMI;
53885627b23Sjakllsch 	bus_space_write_4(bst, fpcih, T_XUSB_CFG_ARU_MAILBOX_CMD_REG, val);
53985627b23Sjakllsch 
54085627b23Sjakllsch 	bool sendresp = true;
54185627b23Sjakllsch 	u_int rate;
54285627b23Sjakllsch 
54385627b23Sjakllsch 	const uint32_t data = __SHIFTOUT(msg, MAILBOX_DATA_DATA);
54485627b23Sjakllsch 	const uint8_t type = __SHIFTOUT(msg, MAILBOX_DATA_TYPE);
54585627b23Sjakllsch 
54685627b23Sjakllsch 	switch (type) {
54785627b23Sjakllsch 	case 2:
54885627b23Sjakllsch 	case 3:
54967b89dbeSjmcneill 		DPRINTF(sc->sc_dev, "FALC_CLOCK %u\n", data * 1000);
55085627b23Sjakllsch 		break;
55185627b23Sjakllsch 	case 4:
55285627b23Sjakllsch 	case 5:
553055a5e80Sskrll 		if (psc->sc_txd->txd_scale_ss_clock) {
55467b89dbeSjmcneill 			DPRINTF(sc->sc_dev, "SSPI_CLOCK %u\n", data * 1000);
55585627b23Sjakllsch 			rate = clk_get_rate(psc->sc_clk_ss_src);
55667b89dbeSjmcneill 			DPRINTF(sc->sc_dev, "rate of psc->sc_clk_ss_src %u\n",
55785627b23Sjakllsch 			    rate);
55885627b23Sjakllsch 			error = clk_set_rate(psc->sc_clk_ss_src, data * 1000);
55985627b23Sjakllsch 			if (error != 0)
56085627b23Sjakllsch 				goto clk_fail;
56185627b23Sjakllsch 			rate = clk_get_rate(psc->sc_clk_ss_src);
56267b89dbeSjmcneill 			DPRINTF(sc->sc_dev,
56385627b23Sjakllsch 			    "rate of psc->sc_clk_ss_src %u after\n", rate);
56485627b23Sjakllsch 			if (data == (rate / 1000)) {
56585627b23Sjakllsch 				msg = __SHIFTIN(128, MAILBOX_DATA_TYPE) |
56685627b23Sjakllsch 				      __SHIFTIN(rate / 1000, MAILBOX_DATA_DATA);
56785627b23Sjakllsch 			} else
56885627b23Sjakllsch clk_fail:
56985627b23Sjakllsch 				msg = __SHIFTIN(129, MAILBOX_DATA_TYPE) |
57085627b23Sjakllsch 				      __SHIFTIN(rate / 1000, MAILBOX_DATA_DATA);
57157030377Sjmcneill 		} else {
57257030377Sjmcneill 			msg = __SHIFTIN(128, MAILBOX_DATA_TYPE) |
57357030377Sjmcneill 			      __SHIFTIN(data, MAILBOX_DATA_DATA);
57457030377Sjmcneill 		}
57585627b23Sjakllsch 		xusb_mailbox_send(psc, msg);
57685627b23Sjakllsch 		break;
57785627b23Sjakllsch 	case 9:
57885627b23Sjakllsch 		msg = __SHIFTIN(data, MAILBOX_DATA_DATA) |
57985627b23Sjakllsch 		      __SHIFTIN(128, MAILBOX_DATA_TYPE);
58085627b23Sjakllsch 		xusb_mailbox_send(psc, msg);
58185627b23Sjakllsch 		break;
58285627b23Sjakllsch 	case 6:
58385627b23Sjakllsch 	case 128:
58485627b23Sjakllsch 	case 129:
58585627b23Sjakllsch 		sendresp = false;
58685627b23Sjakllsch 		break;
58785627b23Sjakllsch 	default:
58885627b23Sjakllsch 		sendresp = false;
58985627b23Sjakllsch 		break;
59085627b23Sjakllsch 	}
59185627b23Sjakllsch 
59285627b23Sjakllsch 	if (sendresp == false)
59385627b23Sjakllsch 		bus_space_write_4(bst, fpcih, T_XUSB_CFG_ARU_MAILBOX_OWNER_REG,
59485627b23Sjakllsch 		    MAILBOX_OWNER_NONE);
59585627b23Sjakllsch 
59685627b23Sjakllsch 	return irv;
59785627b23Sjakllsch }
59885627b23Sjakllsch 
59985627b23Sjakllsch static void
tegra_xusb_init_regulators(struct tegra_xusb_softc * const psc)60069339524Sjmcneill tegra_xusb_init_regulators(struct tegra_xusb_softc * const psc)
60169339524Sjmcneill {
602055a5e80Sskrll 
60369339524Sjmcneill 	device_t dev = psc->sc_xhci.sc_dev;
60469339524Sjmcneill 	const int phandle = psc->sc_phandle;
60569339524Sjmcneill 	struct fdtbus_regulator *reg;
60669339524Sjmcneill 	int n, error;
60769339524Sjmcneill 
608055a5e80Sskrll 	for (n = 0; n < psc->sc_txd->txd_nsupplies; n++) {
609055a5e80Sskrll 		if (!of_hasprop(phandle, psc->sc_txd->txd_supplies[n]))
61069339524Sjmcneill 			continue;
611055a5e80Sskrll 		reg = fdtbus_regulator_acquire(phandle, psc->sc_txd->txd_supplies[n]);
61269339524Sjmcneill 		if (reg == NULL) {
61369339524Sjmcneill 			aprint_error_dev(dev, "couldn't acquire supply '%s'\n",
614055a5e80Sskrll 			    psc->sc_txd->txd_supplies[n]);
61569339524Sjmcneill 			continue;
61669339524Sjmcneill 		}
61769339524Sjmcneill 		error = fdtbus_regulator_enable(reg);
61869339524Sjmcneill 		if (error != 0)
61969339524Sjmcneill 			aprint_error_dev(dev, "couldn't enable supply '%s': %d\n",
620055a5e80Sskrll 			    psc->sc_txd->txd_supplies[n], error);
62169339524Sjmcneill 	}
62269339524Sjmcneill }
62369339524Sjmcneill 
62469339524Sjmcneill static void
tegra_xusb_init(struct tegra_xusb_softc * const psc)62585627b23Sjakllsch tegra_xusb_init(struct tegra_xusb_softc * const psc)
62685627b23Sjakllsch {
62785627b23Sjakllsch 	struct xhci_softc * const sc = &psc->sc_xhci;
62885627b23Sjakllsch 	const bus_space_tag_t bst = sc->sc_iot;
62985627b23Sjakllsch 	const bus_space_handle_t ipfsh = psc->sc_bsh_ipfs;
63085627b23Sjakllsch 	const bus_space_handle_t fpcih = psc->sc_bsh_fpci;
63185627b23Sjakllsch 
63267b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s()\n", __func__);
63385627b23Sjakllsch 
63467b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x0 = 0x%x\n", __func__,
63585627b23Sjakllsch 	    bus_space_read_4(bst, ipfsh, 0x0));
63685627b23Sjakllsch 
63767b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x40 = 0x%x\n", __func__,
63885627b23Sjakllsch 	    bus_space_read_4(bst, ipfsh, 0x40));
63985627b23Sjakllsch 
64067b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x80 = 0x%x\n", __func__,
64185627b23Sjakllsch 	    bus_space_read_4(bst, ipfsh, 0x80));
64285627b23Sjakllsch 	/* FPCI_BAR0_START and FPCI_BAR0_ACCESS_TYPE */
64385627b23Sjakllsch 	bus_space_write_4(bst, ipfsh, 0x80, 0x00100000);
64467b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x80 = 0x%x\n", __func__,
64585627b23Sjakllsch 	    bus_space_read_4(bst, ipfsh, 0x80));
64685627b23Sjakllsch 
64767b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x180 = 0x%x\n", __func__,
64885627b23Sjakllsch 	    bus_space_read_4(bst, ipfsh, 0x180));
64985627b23Sjakllsch 	/* EN_FPCI */
65085627b23Sjakllsch 	tegra_reg_set_clear(bst, ipfsh, 0x180, 1, 0);
65167b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x180 = 0x%x\n", __func__,
65285627b23Sjakllsch 	    bus_space_read_4(bst, ipfsh, 0x180));
65385627b23Sjakllsch 
65467b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s fpci PCI_COMMAND_STATUS_REG = 0x%x\n",
65585627b23Sjakllsch 	    __func__, bus_space_read_4(bst, fpcih, PCI_COMMAND_STATUS_REG));
65685627b23Sjakllsch 	tegra_reg_set_clear(bst, fpcih, PCI_COMMAND_STATUS_REG,
65785627b23Sjakllsch 	    PCI_COMMAND_MASTER_ENABLE|PCI_COMMAND_MEM_ENABLE, 0x0);
65867b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s fpci PCI_COMMAND_STATUS_REG = 0x%x\n",
65985627b23Sjakllsch 	    __func__, bus_space_read_4(bst, fpcih, PCI_COMMAND_STATUS_REG));
66085627b23Sjakllsch 
66167b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s fpci PCI_BAR0 = 0x%x\n", __func__,
66285627b23Sjakllsch 	    bus_space_read_4(bst, fpcih, PCI_BAR0));
66385627b23Sjakllsch 	/* match FPCI BAR0 to above */
66485627b23Sjakllsch 	bus_space_write_4(bst, fpcih, PCI_BAR0, 0x10000000);
66567b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s fpci PCI_BAR0 = 0x%x\n", __func__,
66685627b23Sjakllsch 	    bus_space_read_4(bst, fpcih, PCI_BAR0));
66785627b23Sjakllsch 
66867b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x188 = 0x%x\n", __func__,
66985627b23Sjakllsch 	    bus_space_read_4(bst, ipfsh, 0x188));
67085627b23Sjakllsch 	tegra_reg_set_clear(bst, ipfsh, 0x188, __BIT(16), 0);
67167b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s ipfs 0x188 = 0x%x\n", __func__,
67285627b23Sjakllsch 	    bus_space_read_4(bst, ipfsh, 0x188));
67385627b23Sjakllsch 
67467b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s fpci 0x1bc = 0x%x\n", __func__,
67585627b23Sjakllsch 	    bus_space_read_4(bst, fpcih, 0x1bc));
67685627b23Sjakllsch 	bus_space_write_4(bst, fpcih, 0x1bc, 0x80);
67767b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "%s fpci 0x1bc = 0x%x\n", __func__,
67885627b23Sjakllsch 	    bus_space_read_4(bst, fpcih, 0x1bc));
67985627b23Sjakllsch }
68085627b23Sjakllsch 
68185627b23Sjakllsch static int
fw_dma_alloc(struct tegra_xusb_softc * const psc,size_t size,size_t align,struct fw_dma * const p)68285627b23Sjakllsch fw_dma_alloc(struct tegra_xusb_softc * const psc, size_t size, size_t align,
68385627b23Sjakllsch     struct fw_dma * const p)
68485627b23Sjakllsch {
68585627b23Sjakllsch 	struct xhci_softc * const sc = &psc->sc_xhci;
68685627b23Sjakllsch 	const bus_dma_tag_t dmat = sc->sc_bus.ub_dmatag;
68785627b23Sjakllsch 	int err;
68885627b23Sjakllsch 
68985627b23Sjakllsch 	p->size = size;
69085627b23Sjakllsch 	err = bus_dmamem_alloc(dmat, p->size, align, 0, p->segs,
69185627b23Sjakllsch 	    sizeof(p->segs) / sizeof(p->segs[0]), &p->nsegs, BUS_DMA_NOWAIT);
69285627b23Sjakllsch 	if (err)
69385627b23Sjakllsch 		return err;
69485627b23Sjakllsch 	err = bus_dmamem_map(dmat, p->segs, p->nsegs, p->size, &p->addr,
69585627b23Sjakllsch 	    BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
69685627b23Sjakllsch 	if (err)
69785627b23Sjakllsch 		goto free;
69885627b23Sjakllsch 	err = bus_dmamap_create(dmat, p->size, 1, p->size, 0, BUS_DMA_NOWAIT,
69985627b23Sjakllsch 	    &p->map);
70085627b23Sjakllsch 	if (err)
70185627b23Sjakllsch 		goto unmap;
70285627b23Sjakllsch 	err = bus_dmamap_load(dmat, p->map, p->addr, p->size, NULL,
70385627b23Sjakllsch 	    BUS_DMA_NOWAIT);
70485627b23Sjakllsch 	if (err)
70585627b23Sjakllsch 		goto destroy;
70685627b23Sjakllsch 
70785627b23Sjakllsch 	return 0;
70885627b23Sjakllsch 
70985627b23Sjakllsch destroy:
71085627b23Sjakllsch 	bus_dmamap_destroy(dmat, p->map);
71185627b23Sjakllsch unmap:
71285627b23Sjakllsch 	bus_dmamem_unmap(dmat, p->addr, p->size);
71385627b23Sjakllsch free:
71485627b23Sjakllsch 	bus_dmamem_free(dmat, p->segs, p->nsegs);
71585627b23Sjakllsch 
71685627b23Sjakllsch 	return err;
71785627b23Sjakllsch }
71885627b23Sjakllsch 
71985627b23Sjakllsch static void
fw_dma_free(struct tegra_xusb_softc * const psc,struct fw_dma * const p)72085627b23Sjakllsch fw_dma_free(struct tegra_xusb_softc * const psc, struct fw_dma * const p)
72185627b23Sjakllsch {
72285627b23Sjakllsch 	const struct xhci_softc * const sc = &psc->sc_xhci;
72385627b23Sjakllsch 	const bus_dma_tag_t dmat = sc->sc_bus.ub_dmatag;
72485627b23Sjakllsch 
72585627b23Sjakllsch 	bus_dmamap_unload(dmat, p->map);
72685627b23Sjakllsch 	bus_dmamap_destroy(dmat, p->map);
72785627b23Sjakllsch 	bus_dmamem_unmap(dmat, p->addr, p->size);
72885627b23Sjakllsch 	bus_dmamem_free(dmat, p->segs, p->nsegs);
72985627b23Sjakllsch }
73085627b23Sjakllsch 
73185627b23Sjakllsch #define FWHEADER_BOOT_CODETAG 8
73285627b23Sjakllsch #define FWHEADER_BOOT_CODESIZE 12
73385627b23Sjakllsch #define FWHEADER_FWIMG_LEN 100
73485627b23Sjakllsch #define FWHEADER__LEN 256
73585627b23Sjakllsch 
736030df658Sjmcneill static int
tegra_xusb_open_fw(struct tegra_xusb_softc * const psc)737a7c423b9Sjmcneill tegra_xusb_open_fw(struct tegra_xusb_softc * const psc)
73885627b23Sjakllsch {
73985627b23Sjakllsch 	struct xhci_softc * const sc = &psc->sc_xhci;
74085627b23Sjakllsch 	firmware_handle_t fw;
741a7c423b9Sjmcneill 	size_t firmware_size = 0;
74285627b23Sjakllsch 	void *firmware_image;
743a7c423b9Sjmcneill 	const char *fw_path = NULL;
744a7c423b9Sjmcneill 	void *fw_static = NULL;
745a7c423b9Sjmcneill 	int error;
74685627b23Sjakllsch 
747055a5e80Sskrll 	switch (psc->sc_txd->txd_type) {
748a7c423b9Sjmcneill 	case XUSB_T124:
74985627b23Sjakllsch #if defined(TEGRA124_XUSB_BIN_STATIC)
7505ea5576aSjakllsch 		firmware_size = (uintptr_t)&_binary_tegra124_xusb_bin_end
7515ea5576aSjakllsch 		    - (uintptr_t)&_binary_tegra124_xusb_bin_start;
7525971ec21Sjakllsch 		fw_static = __UNCONST(_binary_tegra124_xusb_bin_start);
75385627b23Sjakllsch #else
754a7c423b9Sjmcneill 		fw_path = "nvidia/tegra124";
755a7c423b9Sjmcneill #endif
756a7c423b9Sjmcneill 		break;
757a7c423b9Sjmcneill 	case XUSB_T210:
758a7c423b9Sjmcneill #if defined(TEGRA210_XUSB_BIN_STATIC)
7595ea5576aSjakllsch 		firmware_size = (uintptr_t)&_binary_tegra210_xusb_bin_end
7605ea5576aSjakllsch 		    - (uintptr_t)&_binary_tegra210_xusb_bin_start;
7615971ec21Sjakllsch 		fw_static = __UNCONST(_binary_tegra210_xusb_bin_start);
762a7c423b9Sjmcneill #else
763a7c423b9Sjmcneill 		fw_path = "nvidia/tegra210";
764a7c423b9Sjmcneill #endif
765a7c423b9Sjmcneill 		break;
766a7c423b9Sjmcneill 	default:
767a7c423b9Sjmcneill 		return EINVAL;
768a7c423b9Sjmcneill 	}
769a7c423b9Sjmcneill 
770a7c423b9Sjmcneill 	if (fw_path != NULL) {
771a7c423b9Sjmcneill 		error = firmware_open(fw_path, "xusb.bin", &fw);
772a7c423b9Sjmcneill 		if (error != 0) {
77385627b23Sjakllsch 			aprint_error_dev(sc->sc_dev,
774a7c423b9Sjmcneill 			    "couldn't load firmware from %s/xusb.bin: %d\n",
775a7c423b9Sjmcneill 			    fw_path, error);
776030df658Sjmcneill 			return error;
77785627b23Sjakllsch 		}
77885627b23Sjakllsch 		firmware_size = firmware_get_size(fw);
77985627b23Sjakllsch 	}
78085627b23Sjakllsch 
781a7c423b9Sjmcneill 	error = fw_dma_alloc(psc, firmware_size, PAGE_SIZE,
782a7c423b9Sjmcneill 	    &psc->sc_fw_dma);
783a7c423b9Sjmcneill 	if (error != 0)
784a7c423b9Sjmcneill 		return error;
78585627b23Sjakllsch 	firmware_image = psc->sc_fw_dma.addr;
78685627b23Sjakllsch 
787a7c423b9Sjmcneill 	if (fw_path != NULL) {
78885627b23Sjakllsch 		error = firmware_read(fw, 0, firmware_image, firmware_size);
78985627b23Sjakllsch 		if (error != 0) {
79085627b23Sjakllsch 			fw_dma_free(psc, &psc->sc_fw_dma);
79185627b23Sjakllsch 			firmware_close(fw);
792030df658Sjmcneill 			return error;
79385627b23Sjakllsch 		}
79485627b23Sjakllsch 		firmware_close(fw);
795a7c423b9Sjmcneill 	} else {
796a7c423b9Sjmcneill 		memcpy(firmware_image, fw_static, firmware_size);
797a7c423b9Sjmcneill 	}
798a7c423b9Sjmcneill 
799a7c423b9Sjmcneill 	return tegra_xusb_load_fw(psc, firmware_image, firmware_size);
800a7c423b9Sjmcneill }
801a7c423b9Sjmcneill 
802a7c423b9Sjmcneill static int
tegra_xusb_load_fw(struct tegra_xusb_softc * const psc,void * firmware_image,size_t firmware_size)803a7c423b9Sjmcneill tegra_xusb_load_fw(struct tegra_xusb_softc * const psc, void *firmware_image,
804a7c423b9Sjmcneill     size_t firmware_size)
805a7c423b9Sjmcneill {
806a7c423b9Sjmcneill 	struct xhci_softc * const sc = &psc->sc_xhci;
807a7c423b9Sjmcneill 	const uint8_t *header;
80885627b23Sjakllsch 
80985627b23Sjakllsch 	header = firmware_image;
81085627b23Sjakllsch 
81185627b23Sjakllsch 	const uint32_t fwimg_len = le32dec(&header[FWHEADER_FWIMG_LEN]);
81285627b23Sjakllsch 	const uint32_t boot_codetag = le32dec(&header[FWHEADER_BOOT_CODETAG]);
81385627b23Sjakllsch 	const uint32_t boot_codesize = le32dec(&header[FWHEADER_BOOT_CODESIZE]);
81485627b23Sjakllsch 
81585627b23Sjakllsch 	if (fwimg_len != firmware_size)
81667b89dbeSjmcneill 		aprint_error_dev(sc->sc_dev, "fwimg_len mismatch %u != %zu\n",
81785627b23Sjakllsch 		    fwimg_len, firmware_size);
81885627b23Sjakllsch 
81985627b23Sjakllsch 	bus_dmamap_sync(sc->sc_bus.ub_dmatag, psc->sc_fw_dma.map, 0,
82085627b23Sjakllsch 	    firmware_size, BUS_DMASYNC_PREWRITE);
82185627b23Sjakllsch 
82267b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_CPUCTL 0x%x\n",
82385627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_CPUCTL_REG));
82467b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_ILOAD_BASE_LO 0x%x\n",
82585627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_ILOAD_BASE_LO_REG));
82685627b23Sjakllsch 
82767b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_ILOAD_ATTR 0x%x\n",
82885627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_ILOAD_ATTR_REG));
82985627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_MEMPOOL_ILOAD_ATTR_REG,
83085627b23Sjakllsch 	    fwimg_len);
83167b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_ILOAD_ATTR 0x%x\n",
83285627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_ILOAD_ATTR_REG));
83385627b23Sjakllsch 
83485627b23Sjakllsch 	const uint64_t fwbase = psc->sc_fw_dma.map->dm_segs[0].ds_addr +
83585627b23Sjakllsch 	    FWHEADER__LEN;
83685627b23Sjakllsch 
83785627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_MEMPOOL_ILOAD_BASE_HI_REG, fwbase >> 32);
83885627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_MEMPOOL_ILOAD_BASE_LO_REG, fwbase);
83967b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_ILOAD_BASE_LO 0x%x\n",
84085627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_ILOAD_BASE_LO_REG));
84167b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_ILOAD_BASE_HI 0x%x\n",
84285627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_ILOAD_BASE_HI_REG));
84385627b23Sjakllsch 
84467b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_APMAP 0x%x\n",
84585627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_APMAP_REG));
84685627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_MEMPOOL_APMAP_REG,
84785627b23Sjakllsch 	    XUSB_CSB_MEMPOOL_APMAP_BOOTPATH);
84867b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_APMAP 0x%x\n",
84985627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_APMAP_REG));
85085627b23Sjakllsch 
85167b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_L2IMEMOP_TRIG 0x%x\n",
85285627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG_REG));
85385627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG_REG,
85485627b23Sjakllsch 	    __SHIFTIN(ACTION_L2IMEM_INVALIDATE_ALL,
85585627b23Sjakllsch 		XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG_ACTION));
85667b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_L2IMEMOP_TRIG 0x%x\n",
85785627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG_REG));
85885627b23Sjakllsch 
85985627b23Sjakllsch 	const u_int code_tag_blocks =
86085627b23Sjakllsch 	    howmany(boot_codetag, IMEM_BLOCK_SIZE);
86185627b23Sjakllsch 	const u_int code_size_blocks =
86285627b23Sjakllsch 	    howmany(boot_codesize, IMEM_BLOCK_SIZE);
86385627b23Sjakllsch 	const u_int code_blocks = code_tag_blocks + code_size_blocks;
86485627b23Sjakllsch 
86567b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_L2IMEMOP_SIZE 0x%x\n",
86685627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_L2IMEMOP_SIZE_REG));
86785627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_MEMPOOL_L2IMEMOP_SIZE_REG,
86885627b23Sjakllsch 	    __SHIFTIN(code_tag_blocks,
86985627b23Sjakllsch 		XUSB_CSB_MEMPOOL_L2IMEMOP_SIZE_SRC_OFFSET) |
87085627b23Sjakllsch 	    __SHIFTIN(code_size_blocks,
87185627b23Sjakllsch 		XUSB_CSB_MEMPOOL_L2IMEMOP_SIZE_SRC_COUNT));
87267b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_L2IMEMOP_SIZE 0x%x\n",
87385627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_L2IMEMOP_SIZE_REG));
87485627b23Sjakllsch 
87567b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_L2IMEMOP_TRIG 0x%x\n",
87685627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG_REG));
87785627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG_REG,
87885627b23Sjakllsch 	    __SHIFTIN(ACTION_L2IMEM_LOAD_LOCKED_RESULT,
87985627b23Sjakllsch 		XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG_ACTION));
88067b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_CSB_MP_L2IMEMOP_TRIG 0x%x\n",
88185627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG_REG));
88285627b23Sjakllsch 
88367b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_IMFILLCTL 0x%x\n",
88485627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_IMFILLCTL_REG));
88585627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_FALCON_IMFILLCTL_REG, code_size_blocks);
88667b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_IMFILLCTL 0x%x\n",
88785627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_IMFILLCTL_REG));
88885627b23Sjakllsch 
88967b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_IMFILLRNG1 0x%x\n",
89085627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_IMFILLRNG1_REG));
89185627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_FALCON_IMFILLRNG1_REG,
89285627b23Sjakllsch 	    __SHIFTIN(code_tag_blocks, XUSB_CSB_FALCON_IMFILLRNG1_TAG_LO) |
89385627b23Sjakllsch 	    __SHIFTIN(code_blocks, XUSB_CSB_FALCON_IMFILLRNG1_TAG_HI));
89467b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_IMFILLRNG1 0x%x\n",
89585627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_IMFILLRNG1_REG));
89685627b23Sjakllsch 
89767b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_DMACTL 0x%x\n",
89885627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_DMACTL_REG));
89985627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_FALCON_DMACTL_REG, 0);
90067b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_DMACTL 0x%x\n",
90185627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_DMACTL_REG));
90285627b23Sjakllsch 
90367b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_BOOTVEC 0x%x\n",
90485627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_BOOTVEC_REG));
90585627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_FALCON_BOOTVEC_REG,
90685627b23Sjakllsch 	    boot_codetag);
90767b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_BOOTVEC 0x%x\n",
90885627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_BOOTVEC_REG));
90985627b23Sjakllsch 
91067b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_CPUCTL 0x%x\n",
91185627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_CPUCTL_REG));
91285627b23Sjakllsch 	csb_write_4(psc, XUSB_CSB_FALCON_CPUCTL_REG,
91385627b23Sjakllsch 	    XUSB_CSB_FALCON_CPUCTL_STARTCPU);
91467b89dbeSjmcneill 	DPRINTF(sc->sc_dev, "XUSB_FALC_CPUCTL 0x%x\n",
91585627b23Sjakllsch 	    csb_read_4(psc, XUSB_CSB_FALCON_CPUCTL_REG));
916030df658Sjmcneill 
917030df658Sjmcneill 	return 0;
91885627b23Sjakllsch }
91985627b23Sjakllsch 
92085627b23Sjakllsch static uint32_t
csb_read_4(struct tegra_xusb_softc * const psc,bus_size_t csb_offset)92185627b23Sjakllsch csb_read_4(struct tegra_xusb_softc * const psc, bus_size_t csb_offset)
92285627b23Sjakllsch {
92385627b23Sjakllsch 	const uint32_t range = __SHIFTOUT(csb_offset, XUSB_CSB_RANGE);
92485627b23Sjakllsch 	const bus_size_t offset = __SHIFTOUT(csb_offset, XUSB_CSB_OFFSET);
92585627b23Sjakllsch 	const bus_space_tag_t bst = psc->sc_xhci.sc_iot;
92685627b23Sjakllsch 	const bus_space_handle_t fpcih = psc->sc_bsh_fpci;
92785627b23Sjakllsch 
92885627b23Sjakllsch 	bus_space_write_4(bst, fpcih, T_XUSB_CFG_ARU_C11_CSBRANGE_REG, range);
92985627b23Sjakllsch 	return bus_space_read_4(bst, fpcih, T_XUSB_CFG_CSB_BASE_ADDR + offset);
93085627b23Sjakllsch }
93185627b23Sjakllsch 
93285627b23Sjakllsch static void
csb_write_4(struct tegra_xusb_softc * const psc,bus_size_t csb_offset,uint32_t value)93385627b23Sjakllsch csb_write_4(struct tegra_xusb_softc * const psc, bus_size_t csb_offset,
93485627b23Sjakllsch     uint32_t value)
93585627b23Sjakllsch {
93685627b23Sjakllsch 	const uint32_t range = __SHIFTOUT(csb_offset, XUSB_CSB_RANGE);
93785627b23Sjakllsch 	const bus_size_t offset = __SHIFTOUT(csb_offset, XUSB_CSB_OFFSET);
93885627b23Sjakllsch 	const bus_space_tag_t bst = psc->sc_xhci.sc_iot;
93985627b23Sjakllsch 	const bus_space_handle_t fpcih = psc->sc_bsh_fpci;
94085627b23Sjakllsch 
94185627b23Sjakllsch 	bus_space_write_4(bst, fpcih, T_XUSB_CFG_ARU_C11_CSBRANGE_REG, range);
94285627b23Sjakllsch 	bus_space_write_4(bst, fpcih, T_XUSB_CFG_CSB_BASE_ADDR + offset, value);
94385627b23Sjakllsch }
94485627b23Sjakllsch 
94585627b23Sjakllsch static int
xusb_mailbox_send(struct tegra_xusb_softc * const psc,uint32_t msg)94685627b23Sjakllsch xusb_mailbox_send(struct tegra_xusb_softc * const psc, uint32_t msg)
94785627b23Sjakllsch {
94885627b23Sjakllsch 	struct xhci_softc * const sc = &psc->sc_xhci;
94985627b23Sjakllsch 	const bus_space_tag_t bst = psc->sc_xhci.sc_iot;
95085627b23Sjakllsch 	const bus_space_handle_t fpcih = psc->sc_bsh_fpci;
95185627b23Sjakllsch 	uint32_t val;
95285627b23Sjakllsch 	bool wait = false;
95385627b23Sjakllsch 
95485627b23Sjakllsch 	const uint8_t type = __SHIFTOUT(msg, MAILBOX_DATA_TYPE);
95585627b23Sjakllsch 
95685627b23Sjakllsch 	if (!(type == 128 || type == 129)) {
95785627b23Sjakllsch 		val = bus_space_read_4(bst, fpcih,
95885627b23Sjakllsch 		    T_XUSB_CFG_ARU_MAILBOX_OWNER_REG);
95967b89dbeSjmcneill 		DPRINTF(sc->sc_dev, "XUSB_CFG_ARU_MBOX_OWNER 0x%x\n",
96085627b23Sjakllsch 		    val);
96185627b23Sjakllsch 		if (val != MAILBOX_OWNER_NONE) {
96285627b23Sjakllsch 			return EBUSY;
96385627b23Sjakllsch 		}
96485627b23Sjakllsch 
96585627b23Sjakllsch 		bus_space_write_4(bst, fpcih, T_XUSB_CFG_ARU_MAILBOX_OWNER_REG,
96685627b23Sjakllsch 		    MAILBOX_OWNER_SW);
96785627b23Sjakllsch 
96885627b23Sjakllsch 		val = bus_space_read_4(bst, fpcih,
96985627b23Sjakllsch 		    T_XUSB_CFG_ARU_MAILBOX_OWNER_REG);
97067b89dbeSjmcneill 		DPRINTF(sc->sc_dev, "XUSB_CFG_ARU_MBOX_OWNER 0x%x\n",
97185627b23Sjakllsch 		    val);
97285627b23Sjakllsch 		if (val != MAILBOX_OWNER_SW) {
97385627b23Sjakllsch 			return EBUSY;
97485627b23Sjakllsch 		}
97585627b23Sjakllsch 
97685627b23Sjakllsch 		wait = true;
97785627b23Sjakllsch 	}
97885627b23Sjakllsch 
97985627b23Sjakllsch 	bus_space_write_4(bst, fpcih, T_XUSB_CFG_ARU_MAILBOX_DATA_IN_REG, msg);
98085627b23Sjakllsch 
98185627b23Sjakllsch 	tegra_reg_set_clear(bst, fpcih, T_XUSB_CFG_ARU_MAILBOX_CMD_REG,
98285627b23Sjakllsch 	    T_XUSB_CFG_ARU_MAILBOX_CMD_INT_EN |
98385627b23Sjakllsch 	    T_XUSB_CFG_ARU_MAILBOX_CMD_DEST_FALCON, 0);
98485627b23Sjakllsch 
98585627b23Sjakllsch 	if (wait) {
98685627b23Sjakllsch 
98785627b23Sjakllsch 		for (u_int i = 0; i < 2500; i++) {
98885627b23Sjakllsch 			val = bus_space_read_4(bst, fpcih,
98985627b23Sjakllsch 			    T_XUSB_CFG_ARU_MAILBOX_OWNER_REG);
99067b89dbeSjmcneill 			DPRINTF(sc->sc_dev,
99185627b23Sjakllsch 			    "XUSB_CFG_ARU_MBOX_OWNER 0x%x\n", val);
99285627b23Sjakllsch 			if (val == MAILBOX_OWNER_NONE) {
99385627b23Sjakllsch 				break;
99485627b23Sjakllsch 			}
99585627b23Sjakllsch 			DELAY(10);
99685627b23Sjakllsch 		}
99785627b23Sjakllsch 
99885627b23Sjakllsch 		val = bus_space_read_4(bst, fpcih,
99985627b23Sjakllsch 		    T_XUSB_CFG_ARU_MAILBOX_OWNER_REG);
100067b89dbeSjmcneill 		DPRINTF(sc->sc_dev,
100185627b23Sjakllsch 		    "XUSB_CFG_ARU_MBOX_OWNER 0x%x\n", val);
100285627b23Sjakllsch 		if (val != MAILBOX_OWNER_NONE) {
100367b89dbeSjmcneill 			aprint_error_dev(sc->sc_dev,
100485627b23Sjakllsch 			    "timeout, XUSB_CFG_ARU_MBOX_OWNER 0x%x\n", val);
100585627b23Sjakllsch 		}
100685627b23Sjakllsch 	}
100785627b23Sjakllsch 
100885627b23Sjakllsch 	return 0;
100985627b23Sjakllsch }
1010