summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Staaf <robotboy@chromium.org>2015-01-06 09:21:40 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-01-08 00:38:09 +0000
commit18d3bde7f89cb0bf62e3703d1954791dbb2a0df3 (patch)
treea0f34ab79e78d60d7d27ef0132a78d7007caa817
parent5062e5a1714f9a90ffc3227a280bf8d793cdfc83 (diff)
downloadchrome-ec-18d3bde7f89cb0bf62e3703d1954791dbb2a0df3.tar.gz
USB: Add memcpy_from_usbram and update existing memcpy
Previously there was just a memcpy_usbram that copied to USB packet memory, and no routine to copy out. This adds the "from" version and renames and improves to "to" version. The improvement is that the new "to" version correctly handles unaligned beginning and endings of the region to be copied. These need to be read/modify/write accesses since the USB packet ram has to be manipulated in 16-bit chunks. Signed-off-by: Anton Staaf <robotboy@chromium.org> BRANCH=None BUG=None TEST=make buildall -j Verify that discovery-stm32f072 still enumerates and communicates correctly over USB. Change-Id: I94353e66ad0248d4e674abb29f9a88e979767655 Reviewed-on: https://chromium-review.googlesource.com/238764 Tested-by: Anton Staaf <robotboy@chromium.org> Reviewed-by: Vic Yang <victoryang@chromium.org> Commit-Queue: Anton Staaf <robotboy@chromium.org> Trybot-Ready: Anton Staaf <robotboy@chromium.org>
-rw-r--r--board/twinkie/sniffer.c4
-rw-r--r--chip/stm32/usb.c60
-rw-r--r--chip/stm32/usb_hid.c4
-rw-r--r--include/usb.h24
4 files changed, 76 insertions, 16 deletions
diff --git a/board/twinkie/sniffer.c b/board/twinkie/sniffer.c
index e6a0cff0a4..e1f2d5c8c2 100644
--- a/board/twinkie/sniffer.c
+++ b/board/twinkie/sniffer.c
@@ -289,8 +289,8 @@ void sniffer_task(void)
}
ep_buf[u][0] = sample_seq[d >> 3] | (d & 7);
ep_buf[u][1] = sample_tstamp[d >> 3];
- memcpy_usbram(ep_buf[u] + 2,
- samples[d >> 4]+off, EP_PAYLOAD_SIZE);
+ memcpy_to_usbram(ep_buf[u] + 2,
+ samples[d >> 4]+off, EP_PAYLOAD_SIZE);
atomic_clear((uint32_t *)&free_usb, 1 << u);
u = !u;
atomic_clear((uint32_t *)&filled_dma, 1 << d);
diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c
index 82c1337a40..af9082299e 100644
--- a/chip/stm32/usb.c
+++ b/chip/stm32/usb.c
@@ -155,7 +155,7 @@ static void ep0_rx(void)
desc_ptr = desc + USB_MAX_PACKET_SIZE;
len = USB_MAX_PACKET_SIZE;
}
- memcpy_usbram(ep0_buf_tx, desc, len);
+ memcpy_to_usbram(ep0_buf_tx, desc, len);
if (type == USB_DT_CONFIGURATION)
/* set the real descriptor size */
ep0_buf_tx[1] = USB_DESC_SIZE;
@@ -166,7 +166,7 @@ static void ep0_rx(void)
} else if (req == (USB_DIR_IN | (USB_REQ_GET_STATUS << 8))) {
uint16_t zero = 0;
/* Get status */
- memcpy_usbram(ep0_buf_tx, (void *)&zero, 2);
+ memcpy_to_usbram(ep0_buf_tx, (void *)&zero, 2);
btable_ep[0].tx_count = 2;
STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID,
EP_STATUS_OUT /*null OUT transaction */);
@@ -208,7 +208,7 @@ static void ep0_tx(void)
if (desc_ptr) {
/* we have an on-going descriptor transfer */
int len = MIN(desc_left, USB_MAX_PACKET_SIZE);
- memcpy_usbram(ep0_buf_tx, desc_ptr, len);
+ memcpy_to_usbram(ep0_buf_tx, desc_ptr, len);
btable_ep[0].tx_count = len;
desc_left -= len;
desc_ptr += len;
@@ -341,3 +341,57 @@ int usb_is_enabled(void)
{
return (STM32_RCC_APB1ENR & STM32_RCC_PB1_USB) ? 1 : 0;
}
+
+void *memcpy_to_usbram(void *dest, const void *src, size_t n)
+{
+ int i;
+ uint8_t *s = (uint8_t *) src;
+ usb_uint *d = (usb_uint *)((uintptr_t) dest & ~1);
+
+ if ((((uintptr_t) dest) & 1) && n) {
+ /*
+ * The first destination byte is not aligned, perform a read/
+ * modify/write.
+ */
+ *d = (*d & ~0xff00) | (*s << 8);
+ n--;
+ s++;
+ d++;
+ }
+
+ for (i = 0; i < n / 2; i++, s += 2)
+ *d++ = (s[1] << 8) | s[0];
+
+ /*
+ * There is a trailing byte to write into a final USB packet memory
+ * location, use a read/modify/write to be safe.
+ */
+ if (n & 1)
+ *d = (*d & ~0x00ff) | *s;
+
+ return dest;
+}
+
+void *memcpy_from_usbram(void *dest, const void *src, size_t n)
+{
+ int i;
+ usb_uint *s = (usb_uint *)((uintptr_t) src & ~1);
+ uint8_t *d = (uint8_t *) dest;
+
+ if ((((uintptr_t) src) & 1) && n) {
+ *d++ = *s++ >> 8;
+ n--;
+ }
+
+ for (i = 0; i < n / 2; i++) {
+ usb_uint value = *s++;
+
+ *d++ = (value >> 0) & 0xff;
+ *d++ = (value >> 8) & 0xff;
+ }
+
+ if (n & 1)
+ *d = *s;
+
+ return dest;
+}
diff --git a/chip/stm32/usb_hid.c b/chip/stm32/usb_hid.c
index bdcf09c3f8..8b39778202 100644
--- a/chip/stm32/usb_hid.c
+++ b/chip/stm32/usb_hid.c
@@ -88,7 +88,7 @@ static usb_uint hid_ep_buf[HID_REPORT_SIZE / 2] __usb_ram;
void set_keyboard_report(uint64_t rpt)
{
- memcpy_usbram(hid_ep_buf, (const uint8_t *)&rpt, sizeof(rpt));
+ memcpy_to_usbram(hid_ep_buf, &rpt, sizeof(rpt));
/* enable TX */
STM32_TOGGLE_EP(USB_EP_HID, EP_TX_MASK, EP_TX_VALID, 0);
}
@@ -124,7 +124,7 @@ static int hid_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx)
(USB_REQ_GET_DESCRIPTOR << 8))) &&
(ep0_buf_rx[1] == (USB_HID_DT_REPORT << 8))) {
/* Setup : HID specific : Get Report descriptor */
- memcpy_usbram(ep0_buf_tx, report_desc,
+ memcpy_to_usbram(ep0_buf_tx, report_desc,
sizeof(report_desc));
btable_ep[0].tx_count = MIN(ep0_buf_rx[3],
sizeof(report_desc));
diff --git a/include/usb.h b/include/usb.h
index 0c96b19db1..43eb409c1a 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -254,15 +254,21 @@ extern struct stm32_endpoint btable_ep[];
/* Read from USB RAM into a usb_setup_packet struct */
void usb_read_setup_packet(usb_uint *buffer, struct usb_setup_packet *packet);
-/* Copy data to the USB dedicated RAM and take care of the weird addressing */
-static inline void memcpy_usbram(usb_uint *ebuf, const uint8_t *src, int size)
-{
- int i;
- for (i = 0; i < size / 2; i++, src += 2)
- *ebuf++ = src[0] | (src[1] << 8);
- if (size & 1)
- *ebuf++ = src[0];
-}
+/*
+ * Copy data to and from the USB dedicated RAM and take care of the weird
+ * addressing. These functions correctly handle unaligned accesses to the USB
+ * memory. They have the same prototype as memcpy, allowing them to be used
+ * in places that expect memcpy.
+ *
+ * The USB packet RAM is attached to the processor via the AHB2APB bridge. This
+ * bridge performs manipulations of read and write accesses as per the note in
+ * section 2.1 of RM0091. The upshot is that it is OK to read from the packet
+ * RAM using 8-bit or 16-bit accesses, but not 32-bit, and it is only really OK
+ * to write to the packet RAM using 16-bit accesses. Thus custom memcpy like
+ * routines need to be employed.
+ */
+void *memcpy_to_usbram(void *dest, const void *src, size_t n);
+void *memcpy_from_usbram(void *dest, const void *src, size_t n);
/* Compute the address inside dedicate SRAM for the USB controller */
#define usb_sram_addr(x) \