Date: Tue, 27 May 2014 10:01:19 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r266741 - head/sys/dev/usb/controller Message-ID: <201405271001.s4RA1JjQ017311@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Tue May 27 10:01:19 2014 New Revision: 266741 URL: http://svnweb.freebsd.org/changeset/base/266741 Log: Multiple fixes and improvements: - Put "_LE_" into the register access macros to indicate little endian byte order is expected by the hardware. - Avoid using the bounce buffer when not strictly needed. Try to move data directly using bus-space functions first. - Ensure we preserve the reserved bits in the power down mode register. Else the hardware goes into a non-recoverable state. - Always use 32-bit access when writing or reading registers or FIFOs, because the hardware is 32-bit oriented and don't really understand 8- and 16-bit access. - Correct writes to the memory address register. There is no need to shift the register offset. - Correct interval for interrupt endpoints. - Optimise 90ns internal memory buffer read delay. - Rename PDT into PTD, which is how the datasheet writes it. - Add missing programming for activating host controller PTDs. Sponsored by: DARPA, AFRL Modified: head/sys/dev/usb/controller/saf1761_otg.c head/sys/dev/usb/controller/saf1761_otg.h head/sys/dev/usb/controller/saf1761_otg_reg.h Modified: head/sys/dev/usb/controller/saf1761_otg.c ============================================================================== --- head/sys/dev/usb/controller/saf1761_otg.c Tue May 27 09:42:07 2014 (r266740) +++ head/sys/dev/usb/controller/saf1761_otg.c Tue May 27 10:01:19 2014 (r266741) @@ -195,9 +195,9 @@ saf1761_otg_wakeup_peer(struct saf1761_o DPRINTFN(5, "\n"); - temp = SAF1761_READ_2(sc, SOTG_MODE); - SAF1761_WRITE_2(sc, SOTG_MODE, temp | SOTG_MODE_SNDRSU); - SAF1761_WRITE_2(sc, SOTG_MODE, temp & ~SOTG_MODE_SNDRSU); + temp = SAF1761_READ_LE_4(sc, SOTG_MODE); + SAF1761_WRITE_LE_4(sc, SOTG_MODE, temp | SOTG_MODE_SNDRSU); + SAF1761_WRITE_LE_4(sc, SOTG_MODE, temp & ~SOTG_MODE_SNDRSU); /* Wait 8ms for remote wakeup to complete. */ usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); @@ -253,8 +253,8 @@ saf1761_host_channel_free(struct saf1761 return; /* disable channel */ - SAF1761_WRITE_4(sc, SOTG_PDT(td->channel) + SOTG_PDT_DW3, 0); - SAF1761_WRITE_4(sc, SOTG_PDT(td->channel) + SOTG_PDT_DW0, 0); + SAF1761_WRITE_LE_4(sc, SOTG_PTD(td->channel) + SOTG_PTD_DW3, 0); + SAF1761_WRITE_LE_4(sc, SOTG_PTD(td->channel) + SOTG_PTD_DW0, 0); switch (td->ep_type) { case UE_INTERRUPT: @@ -275,49 +275,143 @@ saf1761_host_channel_free(struct saf1761 } } +static uint32_t +saf1761_peek_host_memory_le_4(struct saf1761_otg_softc *sc, uint32_t offset) +{ + SAF1761_WRITE_LE_4(sc, SOTG_MEMORY_REG, offset); + SAF1761_90NS_DELAY(sc); /* read prefetch time is 90ns */ + return (SAF1761_READ_LE_4(sc, offset)); +} + static void -saf1761_read_host_memory_4(struct saf1761_otg_softc *sc, uint32_t offset, - void *buf, uint32_t count) +saf1761_read_host_memory(struct saf1761_otg_softc *sc, + struct saf1761_otg_td *td, uint32_t len) { - if (count == 0) + struct usb_page_search buf_res; + uint32_t offset; + uint32_t count; + + if (len == 0) return; - SAF1761_WRITE_4(sc, SOTG_MEMORY_REG, SOTG_HC_MEMORY_ADDR(offset)); - DELAY(1); /* read prefetch time is 90ns */ - bus_space_read_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl, offset, buf, count); + + offset = SOTG_DATA_ADDR(td->channel); + SAF1761_WRITE_LE_4(sc, SOTG_MEMORY_REG, offset); + SAF1761_90NS_DELAY(sc); /* read prefetch time is 90ns */ + + /* optimised read first */ + while (len > 0) { + usbd_get_page(td->pc, td->offset, &buf_res); + + /* get correct length */ + if (buf_res.length > len) + buf_res.length = len; + + /* check buffer alignment */ + if (((uintptr_t)buf_res.buffer) & 3) + break; + + count = buf_res.length & ~3; + if (count == 0) + break; + + bus_space_read_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl, + offset, buf_res.buffer, count / 4); + + len -= count; + offset += count; + + /* update remainder and offset */ + td->remainder -= count; + td->offset += count; + } + + if (len > 0) { + /* use bounce buffer */ + bus_space_read_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl, + offset, sc->sc_bounce_buffer, (len + 3) / 4); + usbd_copy_in(td->pc, td->offset, + sc->sc_bounce_buffer, len); + + /* update remainder and offset */ + td->remainder -= len; + td->offset += len; + } } static void -saf1761_write_host_memory_4(struct saf1761_otg_softc *sc, uint32_t offset, - void *buf, uint32_t count) +saf1761_write_host_memory(struct saf1761_otg_softc *sc, + struct saf1761_otg_td *td, uint32_t len) { - if (count == 0) + struct usb_page_search buf_res; + uint32_t offset; + uint32_t count; + + if (len == 0) return; - bus_space_write_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl, offset, buf, count); + + offset = SOTG_DATA_ADDR(td->channel); + + /* optimised write first */ + while (len > 0) { + usbd_get_page(td->pc, td->offset, &buf_res); + + /* get correct length */ + if (buf_res.length > len) + buf_res.length = len; + + /* check buffer alignment */ + if (((uintptr_t)buf_res.buffer) & 3) + break; + + count = buf_res.length & ~3; + if (count == 0) + break; + + bus_space_write_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl, + offset, buf_res.buffer, count / 4); + + len -= count; + offset += count; + + /* update remainder and offset */ + td->remainder -= count; + td->offset += count; + } + if (len > 0) { + /* use bounce buffer */ + usbd_copy_out(td->pc, td->offset, sc->sc_bounce_buffer, len); + bus_space_write_region_4((sc)->sc_io_tag, (sc)->sc_io_hdl, + offset, sc->sc_bounce_buffer, (len + 3) / 4); + + /* update remainder and offset */ + td->remainder -= len; + td->offset += len; + } } static uint8_t saf1761_host_setup_tx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td) { - struct usb_device_request req __aligned(4); uint32_t pdt_addr; uint32_t status; uint32_t count; uint32_t temp; if (td->channel < SOTG_HOST_CHANNEL_MAX) { - pdt_addr = SOTG_PDT(td->channel); + pdt_addr = SOTG_PTD(td->channel); - saf1761_read_host_memory_4(sc, pdt_addr + SOTG_PDT_DW3, &status, 1); + status = saf1761_peek_host_memory_le_4(sc, pdt_addr + SOTG_PTD_DW3); + DPRINTFN(5, "STATUS=0x%08x\n", status); - if (status & SOTG_PDT_DW3_ACTIVE) { + if (status & SOTG_PTD_DW3_ACTIVE) { goto busy; - } else if (status & SOTG_PDT_DW3_HALTED) { + } else if (status & SOTG_PTD_DW3_HALTED) { td->error_stall = 1; td->error_any = 1; - } else if (status & SOTG_PDT_DW3_ERRORS) { + } else if (status & SOTG_PTD_DW3_ERRORS) { td->error_any = 1; } - count = (status & SOTG_PDT_DW3_XFER_COUNT); + count = (status & SOTG_PTD_DW3_XFER_COUNT); saf1761_host_channel_free(sc, td); goto complete; @@ -325,42 +419,37 @@ saf1761_host_setup_tx(struct saf1761_otg if (saf1761_host_channel_alloc(sc, td)) goto busy; - if (sizeof(req) != td->remainder) { + count = 8; + + if (count != td->remainder) { td->error_any = 1; goto complete; } - count = sizeof(req); - - usbd_copy_out(td->pc, 0, &req, count); + saf1761_write_host_memory(sc, td, count); - saf1761_write_host_memory_4(sc, SOTG_DATA_ADDR(td->channel), - &req, (count + 3) / 4); + pdt_addr = SOTG_PTD(td->channel); - pdt_addr = SOTG_PDT(td->channel); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW7, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW6, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW5, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW4, 0); - - temp = SOTG_PDT_DW3_ACTIVE | (td->toggle << 25) | SOTG_PDT_DW3_CERR; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW3, temp); + temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) | SOTG_PTD_DW3_CERR; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp); temp = SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW2, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp); temp = td->dw1_value | (2 << 10) /* SETUP PID */ | (td->ep_index >> 1); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW1, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp); temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ | (td->max_packet_size << 18) /* wMaxPacketSize */ | (count << 3) /* transfer count */ | - SOTG_PDT_DW0_VALID; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW0, temp); + SOTG_PTD_DW0_VALID; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp); - td->offset += count; - td->remainder -= count; td->toggle = 1; busy: return (1); /* busy */ @@ -379,21 +468,22 @@ saf1761_host_bulk_data_rx(struct saf1761 uint32_t count; uint8_t got_short; - pdt_addr = SOTG_PDT(td->channel); + pdt_addr = SOTG_PTD(td->channel); - saf1761_read_host_memory_4(sc, pdt_addr + SOTG_PDT_DW3, &status, 1); + status = saf1761_peek_host_memory_le_4(sc, pdt_addr + SOTG_PTD_DW3); + DPRINTFN(5, "STATUS=0x%08x\n", status); - if (status & SOTG_PDT_DW3_ACTIVE) { + if (status & SOTG_PTD_DW3_ACTIVE) { goto busy; - } else if (status & SOTG_PDT_DW3_HALTED) { + } else if (status & SOTG_PTD_DW3_HALTED) { td->error_stall = 1; td->error_any = 1; goto complete; - } else if (status & SOTG_PDT_DW3_ERRORS) { + } else if (status & SOTG_PTD_DW3_ERRORS) { td->error_any = 1; goto complete; } - count = (status & SOTG_PDT_DW3_XFER_COUNT); + count = (status & SOTG_PTD_DW3_XFER_COUNT); got_short = 0; /* verify the packet byte count */ @@ -417,14 +507,7 @@ saf1761_host_bulk_data_rx(struct saf1761 goto complete; } - saf1761_read_host_memory_4(sc, SOTG_DATA_ADDR(td->channel), - sc->sc_bounce_buffer, (count + 3) / 4); - - usbd_copy_in(td->pc, td->offset, - sc->sc_bounce_buffer, count); - - td->remainder -= count; - td->offset += count; + saf1761_read_host_memory(sc, td, count); saf1761_host_channel_free(sc, td); @@ -446,27 +529,27 @@ saf1761_host_bulk_data_rx(struct saf1761 /* receive one more packet */ - pdt_addr = SOTG_PDT(td->channel); + pdt_addr = SOTG_PTD(td->channel); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW7, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW6, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW5, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW4, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, 0); - temp = SOTG_PDT_DW3_ACTIVE | (td->toggle << 25) | SOTG_PDT_DW3_CERR; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW3, temp); + temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) | SOTG_PTD_DW3_CERR; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp); temp = SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW2, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp); temp = td->dw1_value | (1 << 10) /* IN-PID */ | (td->ep_index >> 1); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW1, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp); temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ | (td->max_packet_size << 18) /* wMaxPacketSize */ | (td->max_packet_size << 3) /* transfer count */ | - SOTG_PDT_DW0_VALID; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW0, temp); + SOTG_PTD_DW0_VALID; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp); busy: return (1); /* busy */ complete: @@ -483,16 +566,17 @@ saf1761_host_bulk_data_tx(struct saf1761 if (td->channel < SOTG_HOST_CHANNEL_MAX) { uint32_t status; - pdt_addr = SOTG_PDT(td->channel); + pdt_addr = SOTG_PTD(td->channel); - saf1761_read_host_memory_4(sc, pdt_addr + SOTG_PDT_DW3, &status, 1); + status = saf1761_peek_host_memory_le_4(sc, pdt_addr + SOTG_PTD_DW3); + DPRINTFN(5, "STATUS=0x%08x\n", status); - if (status & SOTG_PDT_DW3_ACTIVE) { + if (status & SOTG_PTD_DW3_ACTIVE) { goto busy; - } else if (status & SOTG_PDT_DW3_HALTED) { + } else if (status & SOTG_PTD_DW3_HALTED) { td->error_stall = 1; td->error_any = 1; - } else if (status & SOTG_PDT_DW3_ERRORS) { + } else if (status & SOTG_PTD_DW3_ERRORS) { td->error_any = 1; } @@ -515,9 +599,7 @@ saf1761_host_bulk_data_tx(struct saf1761 count = td->remainder; } - usbd_copy_out(td->pc, td->offset, sc->sc_bounce_buffer, count); - saf1761_write_host_memory_4(sc, SOTG_DATA_ADDR(td->channel), - sc->sc_bounce_buffer, (count + 3) / 4); + saf1761_write_host_memory(sc, td, count); /* set toggle, if any */ if (td->set_toggle) { @@ -527,30 +609,28 @@ saf1761_host_bulk_data_tx(struct saf1761 /* send one more packet */ - pdt_addr = SOTG_PDT(td->channel); + pdt_addr = SOTG_PTD(td->channel); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW7, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW6, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW5, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW4, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, 0); - temp = SOTG_PDT_DW3_ACTIVE | (td->toggle << 25) | SOTG_PDT_DW3_CERR; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW3, temp); + temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) | SOTG_PTD_DW3_CERR; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp); temp = SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW2, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp); temp = td->dw1_value | (0 << 10) /* OUT-PID */ | (td->ep_index >> 1); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW1, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp); temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ | (td->max_packet_size << 18) /* wMaxPacketSize */ | (count << 3) /* transfer count */ | - SOTG_PDT_DW0_VALID; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW0, temp); + SOTG_PTD_DW0_VALID; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp); - td->offset += count; - td->remainder -= count; td->toggle ^= 1; busy: return (1); /* busy */ @@ -569,19 +649,20 @@ saf1761_host_intr_data_rx(struct saf1761 uint32_t count; uint8_t got_short; - pdt_addr = SOTG_PDT(td->channel); + pdt_addr = SOTG_PTD(td->channel); - saf1761_read_host_memory_4(sc, pdt_addr + SOTG_PDT_DW3, &status, 1); + status = saf1761_peek_host_memory_le_4(sc, pdt_addr + SOTG_PTD_DW3); + DPRINTFN(5, "STATUS=0x%08x\n", status); - if (status & SOTG_PDT_DW3_ACTIVE) { + if (status & SOTG_PTD_DW3_ACTIVE) { goto busy; - } else if (status & SOTG_PDT_DW3_HALTED) { + } else if (status & SOTG_PTD_DW3_HALTED) { td->error_stall = 1; td->error_any = 1; goto complete; } - count = (status & SOTG_PDT_DW3_XFER_COUNT); + count = (status & SOTG_PTD_DW3_XFER_COUNT); got_short = 0; /* verify the packet byte count */ @@ -605,14 +686,7 @@ saf1761_host_intr_data_rx(struct saf1761 goto complete; } - saf1761_read_host_memory_4(sc, SOTG_DATA_ADDR(td->channel), - sc->sc_bounce_buffer, (count + 3) / 4); - - usbd_copy_in(td->pc, td->offset, - sc->sc_bounce_buffer, count); - - td->remainder -= count; - td->offset += count; + saf1761_read_host_memory(sc, td, count); saf1761_host_channel_free(sc, td); @@ -634,31 +708,31 @@ saf1761_host_intr_data_rx(struct saf1761 /* receive one more packet */ - pdt_addr = SOTG_PDT(td->channel); + pdt_addr = SOTG_PTD(td->channel); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW7, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW6, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0); temp = (0xFC << td->uframe) & 0xFF; /* complete split */ - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW5, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, temp); temp = (1U << td->uframe); /* start split */ - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW4, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, temp); - temp = SOTG_PDT_DW3_ACTIVE | (td->toggle << 25) | SOTG_PDT_DW3_CERR; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW3, temp); + temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) | SOTG_PTD_DW3_CERR; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp); - temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) | td->interval; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW2, temp); + temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) | (td->interval & 0xF8); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp); temp = td->dw1_value | (1 << 10) /* IN-PID */ | (td->ep_index >> 1); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW1, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp); temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ | (td->max_packet_size << 18) /* wMaxPacketSize */ | (td->max_packet_size << 3) /* transfer count */ | - SOTG_PDT_DW0_VALID; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW0, temp); + SOTG_PTD_DW0_VALID; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp); busy: return (1); /* busy */ complete: @@ -675,13 +749,14 @@ saf1761_host_intr_data_tx(struct saf1761 if (td->channel < SOTG_HOST_CHANNEL_MAX) { uint32_t status; - pdt_addr = SOTG_PDT(td->channel); + pdt_addr = SOTG_PTD(td->channel); - saf1761_read_host_memory_4(sc, pdt_addr + SOTG_PDT_DW3, &status, 1); + status = saf1761_peek_host_memory_le_4(sc, pdt_addr + SOTG_PTD_DW3); + DPRINTFN(5, "STATUS=0x%08x\n", status); - if (status & SOTG_PDT_DW3_ACTIVE) { + if (status & SOTG_PTD_DW3_ACTIVE) { goto busy; - } else if (status & SOTG_PDT_DW3_HALTED) { + } else if (status & SOTG_PTD_DW3_HALTED) { td->error_stall = 1; td->error_any = 1; } @@ -705,9 +780,7 @@ saf1761_host_intr_data_tx(struct saf1761 count = td->remainder; } - usbd_copy_out(td->pc, td->offset, sc->sc_bounce_buffer, count); - saf1761_write_host_memory_4(sc, SOTG_DATA_ADDR(td->channel), - sc->sc_bounce_buffer, (count + 3) / 4); + saf1761_write_host_memory(sc, td, count); /* set toggle, if any */ if (td->set_toggle) { @@ -717,34 +790,32 @@ saf1761_host_intr_data_tx(struct saf1761 /* send one more packet */ - pdt_addr = SOTG_PDT(td->channel); + pdt_addr = SOTG_PTD(td->channel); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW7, 0); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW6, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW7, 0); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW6, 0); temp = (0xFC << td->uframe) & 0xFF; /* complete split */ - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW5, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW5, temp); temp = (1U << td->uframe); /* start split */ - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW4, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW4, temp); - temp = SOTG_PDT_DW3_ACTIVE | (td->toggle << 25) | SOTG_PDT_DW3_CERR; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW3, temp); + temp = SOTG_PTD_DW3_ACTIVE | (td->toggle << 25) | SOTG_PTD_DW3_CERR; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW3, temp); - temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) | td->interval; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW2, temp); + temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) | (td->interval & 0xF8); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW2, temp); temp = td->dw1_value | (0 << 10) /* OUT-PID */ | (td->ep_index >> 1); - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW1, temp); + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW1, temp); temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ | (td->max_packet_size << 18) /* wMaxPacketSize */ | (count << 3) /* transfer count */ | - SOTG_PDT_DW0_VALID; - SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW0, temp); + SOTG_PTD_DW0_VALID; + SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp); - td->offset += count; - td->remainder -= count; td->toggle ^= 1; busy: return (1); /* busy */ @@ -769,43 +840,117 @@ saf1761_otg_set_address(struct saf1761_o { DPRINTFN(5, "addr=%d\n", addr); - SAF1761_WRITE_1(sc, SOTG_ADDRESS, addr | SOTG_ADDRESS_ENABLE); + SAF1761_WRITE_LE_4(sc, SOTG_ADDRESS, addr | SOTG_ADDRESS_ENABLE); } + static void -saf1761_read_device_fifo_1(struct saf1761_otg_softc *sc, void *buf, uint32_t len) +saf1761_read_device_fifo(struct saf1761_otg_softc *sc, + struct saf1761_otg_td *td, uint32_t len) { - if (len == 0) - return; - bus_space_read_multi_1((sc)->sc_io_tag, (sc)->sc_io_hdl, - SOTG_DATA_PORT, buf, len); + struct usb_page_search buf_res; + uint32_t count; + + /* optimised read first */ + while (len > 0) { + usbd_get_page(td->pc, td->offset, &buf_res); + + /* get correct length */ + if (buf_res.length > len) + buf_res.length = len; + + /* check buffer alignment */ + if (((uintptr_t)buf_res.buffer) & 3) + break; + + count = buf_res.length & ~3; + if (count == 0) + break; + + bus_space_read_multi_4((sc)->sc_io_tag, (sc)->sc_io_hdl, + SOTG_DATA_PORT, buf_res.buffer, count / 4); + + len -= count; + + /* update remainder and offset */ + td->remainder -= count; + td->offset += count; + } + + if (len > 0) { + /* use bounce buffer */ + bus_space_read_multi_4((sc)->sc_io_tag, (sc)->sc_io_hdl, + SOTG_DATA_PORT, sc->sc_bounce_buffer, (len + 3) / 4); + usbd_copy_in(td->pc, td->offset, + sc->sc_bounce_buffer, len); + + /* update remainder and offset */ + td->remainder -= len; + td->offset += len; + } } static void -saf1761_write_device_fifo_1(struct saf1761_otg_softc *sc, void *buf, uint32_t len) +saf1761_write_device_fifo(struct saf1761_otg_softc *sc, + struct saf1761_otg_td *td, uint32_t len) { - if (len == 0) - return; - bus_space_write_multi_1((sc)->sc_io_tag, (sc)->sc_io_hdl, - SOTG_DATA_PORT, buf, len); + struct usb_page_search buf_res; + uint32_t count; + + /* optimised write first */ + while (len > 0) { + usbd_get_page(td->pc, td->offset, &buf_res); + + /* get correct length */ + if (buf_res.length > len) + buf_res.length = len; + + /* check buffer alignment */ + if (((uintptr_t)buf_res.buffer) & 3) + break; + + count = buf_res.length & ~3; + if (count == 0) + break; + + bus_space_write_multi_4((sc)->sc_io_tag, (sc)->sc_io_hdl, + SOTG_DATA_PORT, buf_res.buffer, count / 4); + + len -= count; + + /* update remainder and offset */ + td->remainder -= count; + td->offset += count; + } + if (len > 0) { + /* use bounce buffer */ + usbd_copy_out(td->pc, td->offset, sc->sc_bounce_buffer, len); + bus_space_write_multi_4((sc)->sc_io_tag, (sc)->sc_io_hdl, + SOTG_DATA_PORT, sc->sc_bounce_buffer, (len + 3) / 4); + + /* update remainder and offset */ + td->remainder -= len; + td->offset += len; + } } static uint8_t saf1761_device_setup_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td) { struct usb_device_request req; - uint16_t count; + uint32_t count; /* select the correct endpoint */ - SAF1761_WRITE_1(sc, SOTG_EP_INDEX, SOTG_EP_INDEX_EP0SETUP); + SAF1761_WRITE_LE_4(sc, SOTG_EP_INDEX, SOTG_EP_INDEX_EP0SETUP); + + count = SAF1761_READ_LE_4(sc, SOTG_BUF_LENGTH); /* check buffer status */ - if ((SAF1761_READ_1(sc, SOTG_DCBUFFERSTATUS) & - SOTG_DCBUFFERSTATUS_FILLED_MASK) == 0) + if ((count & SOTG_BUF_LENGTH_FILLED_MASK) == 0) goto busy; - /* read buffer length */ - count = SAF1761_READ_2(sc, SOTG_BUF_LENGTH); + /* get buffer length */ + count &= SOTG_BUF_LENGTH_BUFLEN_MASK; DPRINTFN(5, "count=%u rem=%u\n", count, td->remainder); @@ -813,7 +958,7 @@ saf1761_device_setup_rx(struct saf1761_o td->did_stall = 0; /* clear stall */ - SAF1761_WRITE_1(sc, SOTG_CTRL_FUNC, 0); + SAF1761_WRITE_LE_4(sc, SOTG_CTRL_FUNC, 0); /* verify data length */ if (count != td->remainder) { @@ -827,15 +972,12 @@ saf1761_device_setup_rx(struct saf1761_o goto busy; } /* receive data */ - saf1761_read_device_fifo_1(sc, &req, sizeof(req)); - - /* copy data into real buffer */ - usbd_copy_in(td->pc, 0, &req, sizeof(req)); + saf1761_read_device_fifo(sc, td, sizeof(req)); - td->offset = sizeof(req); - td->remainder = 0; + /* extract SETUP packet again */ + usbd_copy_out(td->pc, 0, &req, sizeof(req)); - /* sneak peek the set address */ + /* sneak peek the set address request */ if ((req.bmRequestType == UT_WRITE_DEVICE) && (req.bRequest == UR_SET_ADDRESS)) { sc->sc_dv_addr = req.wValue[0] & 0x7F; @@ -851,7 +993,7 @@ busy: DPRINTFN(5, "stalling\n"); /* set stall */ - SAF1761_WRITE_1(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_STALL); + SAF1761_WRITE_LE_4(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_STALL); td->did_stall = 1; } @@ -861,17 +1003,17 @@ busy: static uint8_t saf1761_device_data_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td) { - struct usb_page_search buf_res; - uint16_t count; + uint32_t count; uint8_t got_short = 0; if (td->ep_index == 0) { /* select the correct endpoint */ - SAF1761_WRITE_1(sc, SOTG_EP_INDEX, SOTG_EP_INDEX_EP0SETUP); + SAF1761_WRITE_LE_4(sc, SOTG_EP_INDEX, SOTG_EP_INDEX_EP0SETUP); + + count = SAF1761_READ_LE_4(sc, SOTG_BUF_LENGTH); /* check buffer status */ - if ((SAF1761_READ_1(sc, SOTG_DCBUFFERSTATUS) & - SOTG_DCBUFFERSTATUS_FILLED_MASK) != 0) { + if ((count & SOTG_BUF_LENGTH_FILLED_MASK) != 0) { if (td->remainder == 0) { /* @@ -890,23 +1032,24 @@ saf1761_device_data_rx(struct saf1761_ot } } /* select the correct endpoint */ - SAF1761_WRITE_1(sc, SOTG_EP_INDEX, + SAF1761_WRITE_LE_4(sc, SOTG_EP_INDEX, (td->ep_index << SOTG_EP_INDEX_ENDP_INDEX_SHIFT) | SOTG_EP_INDEX_DIR_OUT); /* enable data stage */ if (td->set_toggle) { td->set_toggle = 0; - SAF1761_WRITE_1(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_DSEN); + SAF1761_WRITE_LE_4(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_DSEN); } + count = SAF1761_READ_LE_4(sc, SOTG_BUF_LENGTH); + /* check buffer status */ - if ((SAF1761_READ_1(sc, SOTG_DCBUFFERSTATUS) & - SOTG_DCBUFFERSTATUS_FILLED_MASK) == 0) { + if ((count & SOTG_BUF_LENGTH_FILLED_MASK) == 0) return (1); /* not complete */ - } - /* read buffer length */ - count = SAF1761_READ_2(sc, SOTG_BUF_LENGTH); + + /* get buffer length */ + count &= SOTG_BUF_LENGTH_BUFLEN_MASK; DPRINTFN(5, "rem=%u count=0x%04x\n", td->remainder, count); @@ -928,21 +1071,9 @@ saf1761_device_data_rx(struct saf1761_ot td->error_any = 1; return (0); /* we are complete */ } - while (count > 0) { - usbd_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) - buf_res.length = count; - - /* receive data */ - saf1761_read_device_fifo_1(sc, buf_res.buffer, buf_res.length); + /* receive data */ + saf1761_read_device_fifo(sc, td, count); - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } /* check if we are complete */ if ((td->remainder == 0) || got_short) { if (td->short_pkt) { @@ -957,17 +1088,16 @@ saf1761_device_data_rx(struct saf1761_ot static uint8_t saf1761_device_data_tx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td) { - struct usb_page_search buf_res; - uint16_t count; - uint16_t count_old; + uint32_t count; if (td->ep_index == 0) { /* select the correct endpoint */ - SAF1761_WRITE_1(sc, SOTG_EP_INDEX, SOTG_EP_INDEX_EP0SETUP); + SAF1761_WRITE_LE_4(sc, SOTG_EP_INDEX, SOTG_EP_INDEX_EP0SETUP); + + count = SAF1761_READ_LE_4(sc, SOTG_BUF_LENGTH); /* check buffer status */ - if ((SAF1761_READ_1(sc, SOTG_DCBUFFERSTATUS) & - SOTG_DCBUFFERSTATUS_FILLED_MASK) != 0) { + if ((count & SOTG_BUF_LENGTH_FILLED_MASK) != 0) { DPRINTFN(5, "SETUP abort\n"); /* * USB Host Aborted the transfer. @@ -977,20 +1107,20 @@ saf1761_device_data_tx(struct saf1761_ot } } /* select the correct endpoint */ - SAF1761_WRITE_1(sc, SOTG_EP_INDEX, + SAF1761_WRITE_LE_4(sc, SOTG_EP_INDEX, (td->ep_index << SOTG_EP_INDEX_ENDP_INDEX_SHIFT) | SOTG_EP_INDEX_DIR_IN); + count = SAF1761_READ_LE_4(sc, SOTG_BUF_LENGTH); + /* check buffer status */ - if ((SAF1761_READ_1(sc, SOTG_DCBUFFERSTATUS) & - SOTG_DCBUFFERSTATUS_FILLED_MASK) != 0) { + if ((count & SOTG_BUF_LENGTH_FILLED_MASK) != 0) return (1); /* not complete */ - } /* enable data stage */ if (td->set_toggle) { td->set_toggle = 0; - SAF1761_WRITE_1(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_DSEN); + SAF1761_WRITE_LE_4(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_DSEN); } DPRINTFN(5, "rem=%u\n", td->remainder); @@ -1001,34 +1131,18 @@ saf1761_device_data_tx(struct saf1761_ot td->short_pkt = 1; count = td->remainder; } - count_old = count; - - while (count > 0) { - - usbd_get_page(td->pc, td->offset, &buf_res); - - /* get correct length */ - if (buf_res.length > count) - buf_res.length = count; - - /* transmit data */ - saf1761_write_device_fifo_1(sc, buf_res.buffer, buf_res.length); - - /* update counters */ - count -= buf_res.length; - td->offset += buf_res.length; - td->remainder -= buf_res.length; - } + /* transmit data */ + saf1761_write_device_fifo(sc, td, count); if (td->ep_index == 0) { - if (count_old < SOTG_FS_MAX_PACKET_SIZE) { + if (count < SOTG_FS_MAX_PACKET_SIZE) { /* set end of packet */ - SAF1761_WRITE_1(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_VENDP); + SAF1761_WRITE_LE_4(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_VENDP); } } else { - if (count_old < SOTG_HS_MAX_PACKET_SIZE) { + if (count < SOTG_HS_MAX_PACKET_SIZE) { /* set end of packet */ - SAF1761_WRITE_1(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_VENDP); + SAF1761_WRITE_LE_4(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_VENDP); } } @@ -1045,25 +1159,29 @@ saf1761_device_data_tx(struct saf1761_ot static uint8_t saf1761_device_data_tx_sync(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td) { + uint32_t count; + if (td->ep_index == 0) { /* select the correct endpoint */ - SAF1761_WRITE_1(sc, SOTG_EP_INDEX, SOTG_EP_INDEX_EP0SETUP); + SAF1761_WRITE_LE_4(sc, SOTG_EP_INDEX, SOTG_EP_INDEX_EP0SETUP); + + count = SAF1761_READ_LE_4(sc, SOTG_BUF_LENGTH); /* check buffer status */ - if ((SAF1761_READ_1(sc, SOTG_DCBUFFERSTATUS) & - SOTG_DCBUFFERSTATUS_FILLED_MASK) != 0) { + if ((count & SOTG_BUF_LENGTH_FILLED_MASK) != 0) { DPRINTFN(5, "Faking complete\n"); return (0); /* complete */ } } /* select the correct endpoint */ - SAF1761_WRITE_1(sc, SOTG_EP_INDEX, + SAF1761_WRITE_LE_4(sc, SOTG_EP_INDEX, (td->ep_index << SOTG_EP_INDEX_ENDP_INDEX_SHIFT) | SOTG_EP_INDEX_DIR_IN); + count = SAF1761_READ_LE_4(sc, SOTG_BUF_LENGTH); + /* check buffer status */ - if ((SAF1761_READ_1(sc, SOTG_DCBUFFERSTATUS) & - SOTG_DCBUFFERSTATUS_FILLED_MASK) != 0) + if ((count & SOTG_BUF_LENGTH_FILLED_MASK) != 0) return (1); /* busy */ if (sc->sc_dv_addr != 0xFF) { @@ -1143,7 +1261,7 @@ saf1761_otg_wait_suspend(struct saf1761_ sc->sc_intr_enable &= ~SOTG_DCINTERRUPT_IESUSP; sc->sc_intr_enable |= SOTG_DCINTERRUPT_IERESM; } - SAF1761_WRITE_4(sc, SOTG_DCINTERRUPT_EN, sc->sc_intr_enable); + SAF1761_WRITE_LE_4(sc, SOTG_DCINTERRUPT_EN, sc->sc_intr_enable); } static void @@ -1152,7 +1270,7 @@ saf1761_otg_update_vbus(struct saf1761_o uint16_t status; /* read fresh status */ - status = SAF1761_READ_2(sc, SOTG_STATUS); + status = SAF1761_READ_LE_4(sc, SOTG_STATUS); DPRINTFN(4, "STATUS=0x%04x\n", status); @@ -1188,16 +1306,18 @@ saf1761_otg_interrupt(struct saf1761_otg USB_BUS_LOCK(&sc->sc_bus); - hcstat = SAF1761_READ_4(sc, SOTG_HCINTERRUPT); + hcstat = SAF1761_READ_LE_4(sc, SOTG_HCINTERRUPT); /* acknowledge all host controller interrupts */ - SAF1761_WRITE_4(sc, SOTG_HCINTERRUPT, hcstat); + SAF1761_WRITE_LE_4(sc, SOTG_HCINTERRUPT, hcstat); - status = SAF1761_READ_4(sc, SOTG_DCINTERRUPT); + status = SAF1761_READ_LE_4(sc, SOTG_DCINTERRUPT); /* acknowledge all device controller interrupts */ - SAF1761_WRITE_4(sc, SOTG_DCINTERRUPT, status); + SAF1761_WRITE_LE_4(sc, SOTG_DCINTERRUPT, status); - DPRINTF("DCINTERRUPT=0x%08x HCINTERRUPT=0x%08x SOF=0x%04x\n", - status, hcstat, SAF1761_READ_2(sc, SOTG_FRAME_NUM)); + DPRINTF("DCINTERRUPT=0x%08x HCINTERRUPT=0x%08x SOF=0x%08x " + "FRINDEX=0x%08x\n", status, hcstat, + SAF1761_READ_LE_4(sc, SOTG_FRAME_NUM), + SAF1761_READ_LE_4(sc, SOTG_FRINDEX)); /* update VBUS and ID bits, if any */ if (status & SOTG_DCINTERRUPT_IEVBUS) { @@ -1206,11 +1326,11 @@ saf1761_otg_interrupt(struct saf1761_otg if (status & SOTG_DCINTERRUPT_IEBRST) { /* unlock device */ - SAF1761_WRITE_2(sc, SOTG_UNLOCK_DEVICE, + SAF1761_WRITE_LE_4(sc, SOTG_UNLOCK_DEVICE, SOTG_UNLOCK_DEVICE_CODE); /* Enable device address */ - SAF1761_WRITE_1(sc, SOTG_ADDRESS, + SAF1761_WRITE_LE_4(sc, SOTG_ADDRESS, *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405271001.s4RA1JjQ017311>