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 <nsanders@chromium.org>
Change-Id: Ib859a70981162be58edfa79c7cb267e0084e05e6
Reviewed-on: https://chromium-review.googlesource.com/564150
Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
This commit is contained in:
Nick Sanders
2017-07-11 15:14:37 -07:00
committed by chrome-bot
parent 9fad1adc80
commit 1106dea40d
6 changed files with 188 additions and 6 deletions

View File

@@ -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.

View File

@@ -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)

View File

@@ -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);

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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.