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