Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/nvidia Tegra USB PHY support
details: https://anonhg.NetBSD.org/src/rev/6afbce1c0e86
branches: trunk
changeset: 338073:6afbce1c0e86
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Sat May 09 18:56:51 2015 +0000
description:
Tegra USB PHY support
diffstat:
sys/arch/arm/nvidia/tegra_car.c | 92 +++++++++++++++-
sys/arch/arm/nvidia/tegra_carreg.h | 22 +++-
sys/arch/arm/nvidia/tegra_ehci.c | 204 ++++++++++++++++++++++++++++++++++-
sys/arch/arm/nvidia/tegra_ehcireg.h | 113 +++++++++++++++++++
sys/arch/arm/nvidia/tegra_var.h | 5 +-
5 files changed, 425 insertions(+), 11 deletions(-)
diffs (truncated from 545 to 300 lines):
diff -r 7377bdf7554b -r 6afbce1c0e86 sys/arch/arm/nvidia/tegra_car.c
--- a/sys/arch/arm/nvidia/tegra_car.c Sat May 09 18:49:36 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_car.c Sat May 09 18:56:51 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_car.c,v 1.5 2015/05/09 11:17:59 jmcneill Exp $ */
+/* $NetBSD: tegra_car.c,v 1.6 2015/05/09 18:56:51 jmcneill Exp $ */
/*-
* Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
#include "locators.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_car.c,v 1.5 2015/05/09 11:17:59 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_car.c,v 1.6 2015/05/09 18:56:51 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -283,3 +283,91 @@
return 0;
}
+
+int
+tegra_car_periph_usb_enable(u_int port)
+{
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ bus_size_t rst_reg, enb_reg;
+ uint32_t dev_bit;
+
+ tegra_car_get_bs(&bst, &bsh);
+ switch (port) {
+ case 0:
+ rst_reg = CAR_RST_DEV_L_SET_REG;
+ enb_reg = CAR_CLK_ENB_L_SET_REG;
+ dev_bit = CAR_DEV_L_USBD;
+ break;
+ case 1:
+ rst_reg = CAR_RST_DEV_H_SET_REG;
+ enb_reg = CAR_CLK_ENB_H_SET_REG;
+ dev_bit = CAR_DEV_H_USB2;
+ break;
+ case 2:
+ rst_reg = CAR_RST_DEV_H_SET_REG;
+ enb_reg = CAR_CLK_ENB_H_SET_REG;
+ dev_bit = CAR_DEV_H_USB3;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ /* enter reset */
+ bus_space_write_4(bst, bsh, rst_reg, dev_bit);
+ /* enable clk */
+ bus_space_write_4(bst, bsh, enb_reg, dev_bit);
+
+ /* leave reset */
+ bus_space_write_4(bst, bsh, rst_reg+4, dev_bit);
+
+ return 0;
+}
+
+void
+tegra_car_utmip_init(void)
+{
+ const u_int enable_dly_count = 0x02;
+ const u_int stable_count = 0x33;
+ const u_int active_dly_count = 0x09;
+ const u_int xtal_freq_count = 0x7f;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+
+ tegra_car_get_bs(&bst, &bsh);
+
+ tegra_reg_set_clear(bst, bsh, CAR_UTMIP_PLL_CFG2_REG,
+ __SHIFTIN(stable_count, CAR_UTMIP_PLL_CFG2_STABLE_COUNT) |
+ __SHIFTIN(active_dly_count, CAR_UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT),
+ CAR_UTMIP_PLL_CFG2_STABLE_COUNT |
+ CAR_UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT);
+
+ tegra_reg_set_clear(bst, bsh, CAR_UTMIP_PLL_CFG1_REG,
+ __SHIFTIN(enable_dly_count, CAR_UTMIP_PLL_CFG1_ENABLE_DLY_COUNT) |
+ __SHIFTIN(xtal_freq_count, CAR_UTMIP_PLL_CFG1_XTAL_FREQ_COUNT),
+ CAR_UTMIP_PLL_CFG1_ENABLE_DLY_COUNT |
+ CAR_UTMIP_PLL_CFG1_XTAL_FREQ_COUNT);
+
+ tegra_reg_set_clear(bst, bsh, CAR_UTMIP_PLL_CFG1_REG,
+ 0,
+ CAR_UTMIP_PLL_CFG1_PLLU_POWERDOWN |
+ CAR_UTMIP_PLL_CFG1_PLL_ENABLE_POWERDOWN);
+}
+
+void
+tegra_car_utmip_enable(u_int port)
+{
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ uint32_t bit = 0;
+
+ tegra_car_get_bs(&bst, &bsh);
+
+ switch (port) {
+ case 0: bit = CAR_UTMIP_PLL_CFG2_PD_SAMP_A_POWERDOWN; break;
+ case 1: bit = CAR_UTMIP_PLL_CFG2_PD_SAMP_B_POWERDOWN; break;
+ case 2: bit = CAR_UTMIP_PLL_CFG2_PD_SAMP_C_POWERDOWN; break;
+ }
+
+ tegra_reg_set_clear(bst, bsh, CAR_UTMIP_PLL_CFG2_REG, 0, bit);
+}
diff -r 7377bdf7554b -r 6afbce1c0e86 sys/arch/arm/nvidia/tegra_carreg.h
--- a/sys/arch/arm/nvidia/tegra_carreg.h Sat May 09 18:49:36 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_carreg.h Sat May 09 18:56:51 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_carreg.h,v 1.6 2015/05/09 11:17:59 jmcneill Exp $ */
+/* $NetBSD: tegra_carreg.h,v 1.7 2015/05/09 18:56:51 jmcneill Exp $ */
/*-
* Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -213,4 +213,24 @@
#define CAR_DEV_H_AHBDMA __BIT(1)
#define CAR_DEV_H_MEM __BIT(0)
+#define CAR_UTMIP_PLL_CFG0_REG 0x480
+
+#define CAR_UTMIP_PLL_CFG1_REG 0x484
+#define CAR_UTMIP_PLL_CFG1_ENABLE_DLY_COUNT __BITS(31,27)
+#define CAR_UTMIP_PLL_CFG1_PLLU_POWERUP __BIT(17)
+#define CAR_UTMIP_PLL_CFG1_PLLU_POWERDOWN __BIT(16)
+#define CAR_UTMIP_PLL_CFG1_PLL_ENABLE_POWERUP __BIT(15)
+#define CAR_UTMIP_PLL_CFG1_PLL_ENABLE_POWERDOWN __BIT(14)
+#define CAR_UTMIP_PLL_CFG1_XTAL_FREQ_COUNT __BITS(11,0)
+
+#define CAR_UTMIP_PLL_CFG2_REG 0x488
+#define CAR_UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT __BITS(23,18)
+#define CAR_UTMIP_PLL_CFG2_STABLE_COUNT __BITS(17,6)
+#define CAR_UTMIP_PLL_CFG2_PD_SAMP_C_POWERUP __BIT(5)
+#define CAR_UTMIP_PLL_CFG2_PD_SAMP_C_POWERDOWN __BIT(4)
+#define CAR_UTMIP_PLL_CFG2_PD_SAMP_B_POWERUP __BIT(3)
+#define CAR_UTMIP_PLL_CFG2_PD_SAMP_B_POWERDOWN __BIT(2)
+#define CAR_UTMIP_PLL_CFG2_PD_SAMP_A_POWERUP __BIT(1)
+#define CAR_UTMIP_PLL_CFG2_PD_SAMP_A_POWERDOWN __BIT(0)
+
#endif /* _ARM_TEGRA_CARREG_H */
diff -r 7377bdf7554b -r 6afbce1c0e86 sys/arch/arm/nvidia/tegra_ehci.c
--- a/sys/arch/arm/nvidia/tegra_ehci.c Sat May 09 18:49:36 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_ehci.c Sat May 09 18:56:51 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_ehci.c,v 1.3 2015/05/09 12:07:52 jmcneill Exp $ */
+/* $NetBSD: tegra_ehci.c,v 1.4 2015/05/09 18:56:51 jmcneill Exp $ */
/*-
* Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
#include "locators.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_ehci.c,v 1.3 2015/05/09 12:07:52 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_ehci.c,v 1.4 2015/05/09 18:56:51 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -46,19 +46,27 @@
#include <dev/usb/ehcivar.h>
#include <arm/nvidia/tegra_var.h>
+#include <arm/nvidia/tegra_ehcireg.h>
#define TEGRA_EHCI_REG_OFFSET 0x100
static int tegra_ehci_match(device_t, cfdata_t, void *);
static void tegra_ehci_attach(device_t, device_t, void *);
+static void tegra_ehci_init(struct ehci_softc *);
+
struct tegra_ehci_softc {
struct ehci_softc sc;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
void *sc_ih;
+ u_int sc_port;
struct tegra_gpio_pin *sc_pin_vbus;
};
+static void tegra_ehci_utmip_init(struct tegra_ehci_softc *);
+
CFATTACH_DECL2_NEW(tegra_ehci, sizeof(struct tegra_ehci_softc),
tegra_ehci_match, tegra_ehci_attach, NULL,
ehci_activate, NULL, ehci_childdet);
@@ -79,11 +87,16 @@
const char *pin;
int error;
+ sc->sc_bst = tio->tio_bst;
+ bus_space_subregion(tio->tio_bst, tio->tio_bsh,
+ loc->loc_offset, loc->loc_size, &sc->sc_bsh);
+ sc->sc_port = loc->loc_port;
+
sc->sc.sc_dev = self;
sc->sc.sc_bus.hci_private = &sc->sc;
sc->sc.sc_bus.dmatag = tio->tio_dmat;
sc->sc.sc_bus.usbrev = USBREV_2_0;
- sc->sc.sc_flags = EHCIF_ETTF;
+ sc->sc.sc_flags = 0; /* XXX EHCIF_ETTF */
sc->sc.sc_id_vendor = 0x10de;
strlcpy(sc->sc.sc_vendor, "Tegra", sizeof(sc->sc.sc_vendor));
sc->sc.sc_size = loc->loc_size;
@@ -91,15 +104,27 @@
bus_space_subregion(tio->tio_bst, tio->tio_bsh,
loc->loc_offset + TEGRA_EHCI_REG_OFFSET,
loc->loc_size - TEGRA_EHCI_REG_OFFSET, &sc->sc.ioh);
+ sc->sc.sc_vendor_init = tegra_ehci_init;
aprint_naive("\n");
aprint_normal(": USB%d\n", loc->loc_port + 1);
+ tegra_car_periph_usb_enable(sc->sc_port);
+ delay(2);
+
+ tegra_ehci_utmip_init(sc);
+
if (prop_dictionary_get_cstring_nocopy(prop, "vbus-gpio", &pin)) {
- sc->sc_pin_vbus = tegra_gpio_acquire(pin,
- GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
- if (sc->sc_pin_vbus)
- tegra_gpio_write(sc->sc_pin_vbus, 1);
+ const uint32_t v = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+ TEGRA_EHCI_PHY_VBUS_SENSORS_REG);
+ if ((v & TEGRA_EHCI_PHY_VBUS_SENSORS_A_VBUS_VLD_STS) == 0) {
+ sc->sc_pin_vbus = tegra_gpio_acquire(pin,
+ GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
+ if (sc->sc_pin_vbus)
+ tegra_gpio_write(sc->sc_pin_vbus, 1);
+ } else {
+ aprint_normal_dev(self, "VBUS input active\n");
+ }
}
sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
@@ -121,3 +146,168 @@
sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint);
}
+
+static void
+tegra_ehci_init(struct ehci_softc *esc)
+{
+ struct tegra_ehci_softc * const sc = device_private(esc->sc_dev);
+ uint32_t usbmode;
+
+ usbmode = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+ TEGRA_EHCI_USBMODE_REG);
+
+ const u_int cm = __SHIFTOUT(usbmode, TEGRA_EHCI_USBMODE_CM);
+ if (cm != TEGRA_EHCI_USBMODE_CM_HOST) {
+ aprint_verbose_dev(esc->sc_dev, "switching to host mode\n");
+ usbmode &= ~TEGRA_EHCI_USBMODE_CM;
+ usbmode |= __SHIFTIN(TEGRA_EHCI_USBMODE_CM_HOST,
+ TEGRA_EHCI_USBMODE_CM);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh,
+ TEGRA_EHCI_USBMODE_REG, usbmode);
+ }
+
+ /* Parallel transceiver select */
+ tegra_reg_set_clear(sc->sc_bst, sc->sc_bsh,
+ TEGRA_EHCI_HOSTPC1_DEVLC_REG,
+ __SHIFTIN(TEGRA_EHCI_HOSTPC1_DEVLC_PTS_UTMI,
+ TEGRA_EHCI_HOSTPC1_DEVLC_PTS),
+ TEGRA_EHCI_HOSTPC1_DEVLC_PTS |
+ TEGRA_EHCI_HOSTPC1_DEVLC_STS);
+
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, TEGRA_EHCI_TXFILLTUNING_REG,
+ __SHIFTIN(0x10, TEGRA_EHCI_TXFILLTUNING_TXFIFOTHRES));
+}
+
+static void
+tegra_ehci_utmip_init(struct tegra_ehci_softc *sc)
+{
+ bus_space_tag_t bst = sc->sc_bst;
+ bus_space_handle_t bsh = sc->sc_bsh;
+ int retry;
+
+ /* Put UTMIP PHY into reset before programming UTMIP config registers */
+ tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG,
+ TEGRA_EHCI_SUSP_CTRL_UTMIP_RESET, 0);
+
+ /* Enable UTMIP PHY mode */
+ tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_SUSP_CTRL_REG,
+ TEGRA_EHCI_SUSP_CTRL_UTMIP_PHY_ENB, 0);
+
+ /* Stop crystal clock */
+ tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_UTMIP_MISC_CFG1_REG,
+ 0, TEGRA_EHCI_UTMIP_MISC_CFG1_PHY_XTAL_CLOCKEN);
+ delay(1);
+
+ /* Clear session status */
+ tegra_reg_set_clear(bst, bsh, TEGRA_EHCI_PHY_VBUS_SENSORS_REG,
+ 0,
+ TEGRA_EHCI_PHY_VBUS_SENSORS_B_VLD_SW_VALUE |
Home |
Main Index |
Thread Index |
Old Index