From 489a03d0385a1e10eec927d5c8c22be71c88cb92 Mon Sep 17 00:00:00 2001 From: jmatthew Date: Sun, 26 Apr 2015 12:24:03 +0000 Subject: [PATCH] Get dwc2 working on octeon. - transplant the clock setup code from octhci - add a bus space tag to deal with dwc2 using little endian addressing - bump up the rx fifo size, necessary for umass/sd to work tested on an edgerouter lite, which can almost boot by itself now ok uebayasi@ (various parts), miod@ (bus space bits) --- sys/arch/octeon/dev/iobusvar.h | 10 ++- sys/arch/octeon/dev/octdwctwo.c | 120 ++++++++++++++++++++++++++++- sys/arch/octeon/dev/octeon_iobus.c | 10 +-- 3 files changed, 126 insertions(+), 14 deletions(-) diff --git a/sys/arch/octeon/dev/iobusvar.h b/sys/arch/octeon/dev/iobusvar.h index d0086fa5544..2fae7850c1c 100644 --- a/sys/arch/octeon/dev/iobusvar.h +++ b/sys/arch/octeon/dev/iobusvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iobusvar.h,v 1.1 2011/05/08 13:24:55 syuu Exp $ */ +/* $OpenBSD: iobusvar.h,v 1.2 2015/04/26 12:24:03 jmatthew Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -49,4 +49,12 @@ struct iobus_attach_args { bus_dma_tag_t aa_dmat; }; +int iobus_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +void iobus_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t); +int iobus_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); + +void *iobus_space_vaddr(bus_space_tag_t, bus_space_handle_t); + #endif /* _IOBUSVAR_H_ */ diff --git a/sys/arch/octeon/dev/octdwctwo.c b/sys/arch/octeon/dev/octdwctwo.c index 0d99302af8a..b8fb93e5bb5 100644 --- a/sys/arch/octeon/dev/octdwctwo.c +++ b/sys/arch/octeon/dev/octdwctwo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: octdwctwo.c,v 1.5 2015/03/19 10:44:21 mpi Exp $ */ +/* $OpenBSD: octdwctwo.c,v 1.6 2015/04/26 12:24:03 jmatthew Exp $ */ /* * Copyright (c) 2015 Masao Uebayashi @@ -54,6 +54,15 @@ int octdwctwo_set_dma_addr(void *, dma_addr_t, int); u_int64_t octdwctwo_reg2_rd(struct octdwctwo_softc *, bus_size_t); void octdwctwo_reg2_wr(struct octdwctwo_softc *, bus_size_t, u_int64_t); +void octdwctwo_reg_set(struct octdwctwo_softc *, bus_size_t, + u_int64_t); +void octdwctwo_reg_clear(struct octdwctwo_softc *, + bus_size_t, u_int64_t); +u_int32_t octdwctwo_read_4(bus_space_tag_t, bus_space_handle_t, + bus_size_t); +void octdwctwo_write_4(bus_space_tag_t, bus_space_handle_t, + bus_size_t, u_int32_t); + const struct cfattach octdwctwo_ca = { sizeof(struct octdwctwo_softc), octdwctwo_match, octdwctwo_attach, @@ -71,7 +80,7 @@ static struct dwc2_core_params octdwctwo_params = { .speed = 0, .enable_dynamic_fifo = 1, .en_multiple_tx_fifo = 0, - .host_rx_fifo_size = 128/*XXX*/, + .host_rx_fifo_size = 256/*XXX*/, .host_nperio_tx_fifo_size = 128/*XXX*/, .host_perio_tx_fifo_size = 128/*XXX*/, .max_transfer_size = 65535, @@ -95,6 +104,22 @@ static struct dwc2_core_dma_config octdwctwo_dma_config = { .set_dma_addr = octdwctwo_set_dma_addr, }; +/* + * This bus space tag adjusts register addresses to account for + * dwc2 using little endian addressing. dwc2 only does 32bit reads + * and writes, so only those functions are provided. + */ +bus_space_t octdwctwo_tag = { + .bus_base = PHYS_TO_XKPHYS(0, CCA_NC), + .bus_private = NULL, + ._space_read_4 = octdwctwo_read_4, + ._space_write_4 = octdwctwo_write_4, + ._space_map = iobus_space_map, + ._space_unmap = iobus_space_unmap, + ._space_subregion = generic_space_region, + ._space_vaddr = generic_space_vaddr +}; + int octdwctwo_match(struct device *parent, void *match, void *aux) { @@ -106,14 +131,15 @@ octdwctwo_attach(struct device *parent, struct device *self, void *aux) { struct octdwctwo_softc *sc = (struct octdwctwo_softc *)self; struct iobus_attach_args *aa = aux; + uint64_t clk; int rc; - sc->sc_dwc2.sc_iot = aa->aa_bust; + sc->sc_dwc2.sc_iot = &octdwctwo_tag; sc->sc_dwc2.sc_bus.pipe_size = sizeof(struct usbd_pipe); sc->sc_dwc2.sc_bus.dmatag = aa->aa_dmat; sc->sc_dwc2.sc_params = &octdwctwo_params; - rc = bus_space_map(aa->aa_bust, USBC_BASE, USBC_SIZE, + rc = bus_space_map(sc->sc_dwc2.sc_iot, USBC_BASE, USBC_SIZE, 0, &sc->sc_dwc2.sc_ioh); KASSERT(rc == 0); @@ -125,6 +151,55 @@ octdwctwo_attach(struct device *parent, struct device *self, void *aux) 0, &sc->sc_regh2); KASSERT(rc == 0); + /* + * Clock setup. + */ + clk = bus_space_read_8(sc->sc_bust, sc->sc_regh, USBN_CLK_CTL_OFFSET); + clk |= USBN_CLK_CTL_POR; + clk &= ~(USBN_CLK_CTL_HRST | USBN_CLK_CTL_PRST | USBN_CLK_CTL_HCLK_RST | + USBN_CLK_CTL_ENABLE | USBN_CLK_CTL_P_C_SEL | USBN_CLK_CTL_P_RTYPE); + clk |= SET_USBN_CLK_CTL_DIVIDE(0x4ULL) + | SET_USBN_CLK_CTL_DIVIDE2(0x0ULL); + + bus_space_write_8(sc->sc_bust, sc->sc_regh, USBN_CLK_CTL_OFFSET, clk); + bus_space_read_8(sc->sc_bust, sc->sc_regh, USBN_CLK_CTL_OFFSET); + + /* + * Reset HCLK and wait for it to stabilize. + */ + octdwctwo_reg_set(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_HCLK_RST); + delay(64); + + octdwctwo_reg_clear(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_POR); + + /* + * Wait for the PHY clock to start. + */ + delay(1000); + + octdwctwo_reg_set(sc, USBN_USBP_CTL_STATUS_OFFSET, + USBN_USBP_CTL_STATUS_ATE_RESET); + delay(10); + + octdwctwo_reg_clear(sc, USBN_USBP_CTL_STATUS_OFFSET, + USBN_USBP_CTL_STATUS_ATE_RESET); + octdwctwo_reg_set(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_PRST); + + /* + * Select host mode. + */ + octdwctwo_reg_clear(sc, USBN_USBP_CTL_STATUS_OFFSET, + USBN_USBP_CTL_STATUS_HST_MODE); + delay(1); + + octdwctwo_reg_set(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_HRST); + + /* + * Enable clock. + */ + octdwctwo_reg_set(sc, USBN_CLK_CTL_OFFSET, USBN_CLK_CTL_ENABLE); + delay(1); + rc = dwc2_init(&sc->sc_dwc2); if (rc != 0) return; @@ -170,3 +245,40 @@ octdwctwo_reg2_wr(struct octdwctwo_softc *sc, bus_size_t offset, u_int64_t value /* guarantee completion of the store operation on RSL registers*/ bus_space_read_8(sc->sc_bust, sc->sc_regh2, offset); } + +void +octdwctwo_reg_set(struct octdwctwo_softc *sc, bus_size_t offset, + u_int64_t bits) +{ + u_int64_t value; + value = bus_space_read_8(sc->sc_bust, sc->sc_regh, offset); + value |= bits; + + bus_space_write_8(sc->sc_bust, sc->sc_regh, offset, value); + bus_space_read_8(sc->sc_bust, sc->sc_regh, offset); +} + +void +octdwctwo_reg_clear(struct octdwctwo_softc *sc, bus_size_t offset, + u_int64_t bits) +{ + u_int64_t value; + value = bus_space_read_8(sc->sc_bust, sc->sc_regh, offset); + value &= ~bits; + + bus_space_write_8(sc->sc_bust, sc->sc_regh, offset, value); + bus_space_read_8(sc->sc_bust, sc->sc_regh, offset); +} + +u_int32_t +octdwctwo_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + return *(volatile u_int32_t *)(h + (o^4)); +} + +void +octdwctwo_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int32_t v) +{ + *(volatile u_int32_t *)(h + (o^4)) = v; +} diff --git a/sys/arch/octeon/dev/octeon_iobus.c b/sys/arch/octeon/dev/octeon_iobus.c index f7cdb83c22f..84fa5b33178 100644 --- a/sys/arch/octeon/dev/octeon_iobus.c +++ b/sys/arch/octeon/dev/octeon_iobus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: octeon_iobus.c,v 1.9 2015/02/11 05:42:17 uebayasi Exp $ */ +/* $OpenBSD: octeon_iobus.c,v 1.10 2015/04/26 12:24:03 jmatthew Exp $ */ /* * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se) @@ -81,14 +81,6 @@ void iobus_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, void iobus_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, const u_int8_t *, bus_size_t); -int iobus_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, - bus_space_handle_t *); -void iobus_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t); -int iobus_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, - bus_size_t, bus_space_handle_t *); - -void *iobus_space_vaddr(bus_space_tag_t, bus_space_handle_t); - bus_addr_t iobus_pa_to_device(paddr_t); paddr_t iobus_device_to_pa(bus_addr_t); -- 2.20.1