From 1106dea40d3b18fbab2f42a2510d0a7899650db9 Mon Sep 17 00:00:00 2001 From: Nick Sanders Date: Tue, 11 Jul 2017 15:14:37 -0700 Subject: servo_micro: add parity setting Add a control interface to set parity for USB-UART bridge. BRANCH=None BUG=b:37513705 TEST=parity settable on command line or by servod Signed-off-by: Nick Sanders Change-Id: Ib859a70981162be58edfa79c7cb267e0084e05e6 Reviewed-on: https://chromium-review.googlesource.com/564150 Reviewed-by: Nicolas Boichat --- board/servo_micro/board.c | 56 ++++++++++++++++++++++++++++++++++++++++++----- chip/stm32/registers.h | 4 ++++ chip/stm32/usart.c | 40 +++++++++++++++++++++++++++++++++ chip/stm32/usart.h | 12 ++++++++++ chip/stm32/usb-stream.c | 36 ++++++++++++++++++++++++++++++ chip/stm32/usb-stream.h | 46 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 188 insertions(+), 6 deletions(-) diff --git a/board/servo_micro/board.c b/board/servo_micro/board.c index dedfcfdd7a..505a6d628a 100644 --- a/board/servo_micro/board.c +++ b/board/servo_micro/board.c @@ -5,6 +5,7 @@ /* Servo micro board configuration */ #include "common.h" +#include "console.h" #include "ec_version.h" #include "gpio.h" #include "hooks.h" @@ -52,14 +53,15 @@ static struct usart_config const usart2 = usart2_to_usb, usb_to_usart2); -USB_STREAM_CONFIG(usart2_usb, +USB_STREAM_CONFIG_USART_IFACE(usart2_usb, USB_IFACE_USART2_STREAM, USB_STR_USART2_STREAM_NAME, USB_EP_USART2_STREAM, USB_STREAM_RX_SIZE, USB_STREAM_TX_SIZE, usb_to_usart2, - usart2_to_usb) + usart2_to_usb, + usart2) /****************************************************************************** @@ -82,14 +84,15 @@ static struct usart_config const usart3 = usart3_to_usb, usb_to_usart3); -USB_STREAM_CONFIG(usart3_usb, +USB_STREAM_CONFIG_USART_IFACE(usart3_usb, USB_IFACE_USART3_STREAM, USB_STR_USART3_STREAM_NAME, USB_EP_USART3_STREAM, USB_STREAM_RX_SIZE, USB_STREAM_TX_SIZE, usb_to_usart3, - usart3_to_usb) + usart3_to_usb, + usart3) /****************************************************************************** @@ -112,15 +115,56 @@ static struct usart_config const usart4 = usart4_to_usb, usb_to_usart4); -USB_STREAM_CONFIG(usart4_usb, +USB_STREAM_CONFIG_USART_IFACE(usart4_usb, USB_IFACE_USART4_STREAM, USB_STR_USART4_STREAM_NAME, USB_EP_USART4_STREAM, USB_STREAM_RX_SIZE, USB_STREAM_TX_SIZE, usb_to_usart4, - usart4_to_usb) + usart4_to_usb, + usart4) +/****************************************************************************** + * Check parity setting on usarts. + */ +static int command_uart_parity(int argc, char **argv) +{ + int parity, newparity; + struct usart_config const *usart; + char *e; + + if ((argc < 2) || (argc > 3)) + return EC_ERROR_PARAM_COUNT; + + if (!strcasecmp(argv[1], "usart2")) + usart = &usart2; + else if (!strcasecmp(argv[1], "usart3")) + usart = &usart3; + else if (!strcasecmp(argv[1], "usart4")) + usart = &usart4; + else + return EC_ERROR_PARAM1; + + if (argc == 3) { + parity = strtoi(argv[2], &e, 0); + if (*e || (parity < 0) || (parity > 2)) + return EC_ERROR_PARAM2; + + usart_set_parity(usart, parity); + } + + newparity = usart_get_parity(usart); + ccprintf("Parity on %s is %d.\n", argv[1], newparity); + + if ((argc == 3) && (newparity != parity)) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(parity, command_uart_parity, + "usart[2|3|4] [0|1|2]", + "Set parity on uart"); /****************************************************************************** * Define the strings used in our USB descriptors. diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index 03a2c3be00..6c9e2608dc 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -222,6 +222,8 @@ #define STM32_USART_CR1_RXNEIE (1 << 5) #define STM32_USART_CR1_TCIE (1 << 6) #define STM32_USART_CR1_TXEIE (1 << 7) +#define STM32_USART_CR1_PS (1 << 9) +#define STM32_USART_CR1_PCE (1 << 10) #define STM32_USART_CR1_OVER8 (1 << 15) #define STM32_USART_CR2(base) STM32_USART_REG(base, 0x04) #define STM32_USART_CR2_SWAP (1 << 15) @@ -264,6 +266,8 @@ #define STM32_USART_CR1_RXNEIE (1 << 5) #define STM32_USART_CR1_TCIE (1 << 6) #define STM32_USART_CR1_TXEIE (1 << 7) +#define STM32_USART_CR1_PS (1 << 9) +#define STM32_USART_CR1_PCE (1 << 10) #define STM32_USART_CR1_UE (1 << 13) #define STM32_USART_CR1_OVER8 (1 << 15) /* STM32L only */ #define STM32_USART_CR2(base) STM32_USART_REG(base, 0x10) diff --git a/chip/stm32/usart.c b/chip/stm32/usart.c index 549769cb48..d47d13e149 100644 --- a/chip/stm32/usart.c +++ b/chip/stm32/usart.c @@ -102,6 +102,46 @@ void usart_set_baud_f(struct usart_config const *config, int frequency_hz) STM32_USART_BRR(config->hw->base) = div; } +int usart_get_parity(struct usart_config const *config) +{ + intptr_t base = config->hw->base; + + if (!(STM32_USART_CR1(base) & STM32_USART_CR1_PCE)) + return 0; + if (STM32_USART_CR1(base) & STM32_USART_CR1_PS) + return 1; + return 2; +} + +void usart_set_parity(struct usart_config const *config, int parity) +{ + uint32_t ue; + intptr_t base = config->hw->base; + + if ((parity < 0) || (parity > 2)) + return; + + /* Record active state and disable the UART. */ + ue = STM32_USART_CR1(base) & STM32_USART_CR1_UE; + STM32_USART_CR1(base) &= ~STM32_USART_CR1_UE; + + if (parity) { + /* Set parity control enable. */ + STM32_USART_CR1(base) |= STM32_USART_CR1_PCE; + /* Set parity select even/odd bit. */ + if (parity == 2) + STM32_USART_CR1(base) &= ~STM32_USART_CR1_PS; + else + STM32_USART_CR1(base) |= STM32_USART_CR1_PS; + } else { + STM32_USART_CR1(base) &= + ~(STM32_USART_CR1_PCE | STM32_USART_CR1_PS); + } + + /* Restore active state. */ + STM32_USART_CR1(base) |= ue; +} + void usart_interrupt(struct usart_config const *config) { config->tx->interrupt(config); diff --git a/chip/stm32/usart.h b/chip/stm32/usart.h index 875dbfdc76..cbfd8eca21 100644 --- a/chip/stm32/usart.h +++ b/chip/stm32/usart.h @@ -197,6 +197,18 @@ void usart_interrupt(struct usart_config const *config); void usart_set_baud_f0_l(struct usart_config const *config, int frequency_hz); void usart_set_baud_f(struct usart_config const *config, int frequency_hz); +/* + * Allow specification of parity for this usart. + * parity is 0: none, 1: odd, 2: even. + */ +void usart_set_parity(struct usart_config const *config, int parity); + +/* + * Check parity for this usart. + * parity is 0: none, 1: odd, 2: even. + */ +int usart_get_parity(struct usart_config const *config); + /* * Different families provide different ways of clearing the transmit complete * flag. This function will be provided by the family specific implementation. diff --git a/chip/stm32/usb-stream.c b/chip/stm32/usb-stream.c index 313e29e8df..e1ec19d7d4 100644 --- a/chip/stm32/usb-stream.c +++ b/chip/stm32/usb-stream.c @@ -12,6 +12,7 @@ #include "task.h" #include "timer.h" #include "util.h" +#include "usart.h" #include "usb_hw.h" #include "usb-stream.h" @@ -143,3 +144,38 @@ void usb_stream_reset(struct usb_stream_config const *config) (0 << 9) | /* Bulk EP */ (rx_disabled(config) ? EP_RX_NAK : EP_RX_VALID)); } + +int usb_usart_interface(struct usb_stream_config const *config, + struct usart_config const *usart, + int interface, + usb_uint *rx_buf, usb_uint *tx_buf) +{ + struct usb_setup_packet req; + + usb_read_setup_packet(rx_buf, &req); + + if (req.bmRequestType != (USB_DIR_OUT | + USB_TYPE_VENDOR | + USB_RECIP_INTERFACE)) + return -1; + + if (req.wIndex != interface || + req.wLength != 0) + return -1; + + switch (req.bRequest) { + /* Set parity. */ + case USB_USART_SET_PARITY: + usart_set_parity(usart, req.wValue); + break; + + /* TODO(nsanders): support reading parity. */ + /* TODO(nsanders): support baud. */ + default: + return -1; + } + + btable_ep[0].tx_count = 0; + STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT); + return 0; +} diff --git a/chip/stm32/usb-stream.h b/chip/stm32/usb-stream.h index f829009c51..5a584327a5 100644 --- a/chip/stm32/usb-stream.h +++ b/chip/stm32/usb-stream.h @@ -16,6 +16,7 @@ #include "hooks.h" #include "producer.h" #include "queue.h" +#include "usart.h" #include "usb_descriptor.h" #include "usb_hw.h" @@ -230,11 +231,56 @@ extern struct producer_ops const usb_stream_producer_ops; RX_QUEUE, \ TX_QUEUE) +/* Declare a utility interface for setting parity/baud. */ +#define USB_USART_IFACE(NAME, INTERFACE, USART_CFG) \ + static int CONCAT2(NAME, _interface_)(usb_uint *rx_buf, \ + usb_uint *tx_buf) \ + { return usb_usart_interface(&NAME, &USART_CFG, INTERFACE, \ + rx_buf, tx_buf); } \ + USB_DECLARE_IFACE(INTERFACE, \ + CONCAT2(NAME, _interface_)) + +/* This is a medium version for declaring Google serial endpoints */ +#define USB_STREAM_CONFIG_USART_IFACE(NAME, \ + INTERFACE, \ + INTERFACE_NAME, \ + ENDPOINT, \ + RX_SIZE, \ + TX_SIZE, \ + RX_QUEUE, \ + TX_QUEUE, \ + USART_CFG) \ + USB_STREAM_CONFIG_FULL(NAME, \ + INTERFACE, \ + USB_CLASS_VENDOR_SPEC, \ + USB_SUBCLASS_GOOGLE_SERIAL, \ + USB_PROTOCOL_GOOGLE_SERIAL, \ + INTERFACE_NAME, \ + ENDPOINT, \ + RX_SIZE, \ + TX_SIZE, \ + RX_QUEUE, \ + TX_QUEUE); \ + USB_USART_IFACE(NAME, INTERFACE, USART_CFG) + /* * Handle USB and Queue request in a deferred callback. */ void usb_stream_deferred(struct usb_stream_config const *config); +/* + * Handle control interface requests. + */ +enum usb_usart { + USB_USART_REQ_PARITY = 0, + USB_USART_SET_PARITY = 1, + USB_USART_REQ_BAUD = 2, + USB_USART_SET_BAUD = 3, +}; +int usb_usart_interface(struct usb_stream_config const *config, + struct usart_config const *usart, + int interface, usb_uint *rx_buf, usb_uint *tx_buf); + /* * These functions are used by the trampoline functions defined above to * connect USB endpoint events with the generic USB stream driver. -- cgit v1.2.1