g: Clean up pinmux initialization

Now that the pinmux information isn't packed into the GPIO alternate
function table, we can expand it a bit and give the fields nice names,
making the code easier to read and removing a number of bit packing
macros defined in registers.h.

Signed-off-by: Anton Staaf <robotboy@chromium.org>

BRANCH=None
BUG=None
TEST=make buildall -j
     Verified on cr50 hardware
CQ-DEPEND=CL:*249229

Change-Id: I9984bc37faf69b1ba9f1ba66a49596dd22e3b601
Reviewed-on: https://chromium-review.googlesource.com/328979
Commit-Ready: Bill Richardson <wfrichar@chromium.org>
Tested-by: Anton Staaf <robotboy@chromium.org>
Tested-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
Anton Staaf
2016-02-22 14:39:22 -08:00
committed by chrome-bot
parent defe8ea6a9
commit 4f15d2189f
2 changed files with 94 additions and 100 deletions

View File

@@ -84,61 +84,103 @@ void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func)
/* This HW feature is not present in the Cr50 ARM core */
}
struct pinmux {
uint32_t signal;
uint32_t dio;
uint16_t flags;
/*
* A pinmux_config contains the selector offset and selector value for a
* particular pinmux entry.
*/
struct pinmux_config {
uint16_t offset;
uint16_t value;
};
#define GPIO_GPIO(name) GPIO_##name
#define PINMUX(signal, dio, flags) {GPIO_##signal, DIO(dio), flags},
#define PINMUX_CONFIG(name) { \
.offset = CONCAT3(GC_PINMUX_, name, _SEL_OFFSET), \
.value = CONCAT3(GC_PINMUX_, name, _SEL), \
}
/*
* The pinmux struct contains a full description of the connection of a DIO to
* a GPIO, an internal peripheral, or as a direct input. The flag
* DIO_TO_PERIPHERAL is used to select between the two union entries. There
* is no union entry for direct input because it requires no parameters.
*/
struct pinmux {
union {
enum gpio_signal signal;
struct pinmux_config peripheral;
};
struct pinmux_config dio;
uint16_t flags;
};
/*
* These macros are used to add flags indicating the type of mapping requested.
* DIO_TO_PERIPHERAL for FUNC mappings.
* DIO_ENABLE_DIRECT_INPUT for DIRECT mappings.
*/
#define FLAGS_FUNC(name) DIO_TO_PERIPHERAL
#define FLAGS_GPIO(name) 0
#define FLAGS_DIRECT DIO_ENABLE_DIRECT_INPUT
/*
* These macros are used to selectively initialize the anonymous union based
* on the type of pinmux mapping requested (FUNC, GPIO, or DIRECT).
*/
#define PINMUX_FUNC(name) .peripheral = PINMUX_CONFIG(name),
#define PINMUX_GPIO(name) .signal = CONCAT2(GPIO_, name),
#define PINMUX_DIRECT
/*
* Initialize an entry for the pinmux list. The first parameter can be either
* FUNC(name) or GPIO(name) depending on the type of mapping required. The
* second argument is the DIO name to map to. And the final argument is the
* flags set for this mapping, this macro adds the DIO_TO_PERIPHERAL flag for
* a FUNC mapping.
*/
#define PINMUX(name, dio_name, dio_flags) { \
PINMUX_##name \
.dio = PINMUX_CONFIG(DIO##dio_name), \
.flags = dio_flags | FLAGS_##name \
},
static const struct pinmux pinmux_list[] = {
#include "gpio.wrap"
};
static int connect_dio_to_peripheral(struct pinmux const *p)
{
if (p->flags & DIO_OUTPUT)
DIO_SEL_REG(p->dio.offset) = p->peripheral.value;
if (p->flags & DIO_INPUT)
DIO_SEL_REG(p->peripheral.offset) = p->dio.value;
return p->flags & DIO_INPUT;
}
static int connect_dio_to_gpio(struct pinmux const *p)
{
const struct gpio_info *g = gpio_list + p->signal;
int bitnum = GPIO_MASK_TO_NUM(g->mask);
if ((g->flags & GPIO_OUTPUT) || (p->flags & DIO_OUTPUT))
DIO_SEL_REG(p->dio.offset) = GET_GPIO_FUNC(g->port, bitnum);
if ((g->flags & GPIO_INPUT) || (p->flags & DIO_INPUT))
GET_GPIO_SEL_REG(g->port, bitnum) = p->dio.value;
return (g->flags & GPIO_INPUT) || (p->flags & DIO_INPUT);
}
static void connect_pinmux(struct pinmux const *p)
{
uint32_t signal = p->signal;
uint32_t dio = p->dio;
uint16_t flags = p->flags;
if (flags & DIO_ENABLE_DIRECT_INPUT) {
/* enable digital input for direct wired peripheral */
REG_WRITE_MLV(DIO_CTL_REG(dio), DIO_CTL_IE_MASK,
if ((p->flags & DIO_ENABLE_DIRECT_INPUT) ||
((p->flags & DIO_TO_PERIPHERAL) ?
connect_dio_to_peripheral(p) :
connect_dio_to_gpio(p)))
REG_WRITE_MLV(DIO_CTL_REG(p->dio.offset),
DIO_CTL_IE_MASK,
DIO_CTL_IE_LSB, 1);
} else if (FIELD_IS_FUNC(signal)) {
/* Connect peripheral function to DIO */
if (flags & DIO_OUTPUT) {
/* drive DIO from peripheral */
DIO_SEL_REG(dio) = PERIPH_FUNC(signal);
}
if (flags & DIO_INPUT) {
/* drive peripheral from DIO */
PERIPH_SEL_REG(signal) = DIO_FUNC(dio);
/* enable digital input */
REG_WRITE_MLV(DIO_CTL_REG(dio), DIO_CTL_IE_MASK,
DIO_CTL_IE_LSB, 1);
}
} else {
/* Connect GPIO to DIO */
const struct gpio_info *g = gpio_list + FIELD_GET_GPIO(signal);
int bitnum = GPIO_MASK_TO_NUM(g->mask);
if ((g->flags & GPIO_OUTPUT) || (flags & DIO_OUTPUT)) {
/* drive DIO output from GPIO */
DIO_SEL_REG(dio) = GET_GPIO_FUNC(g->port, bitnum);
}
if ((g->flags & GPIO_INPUT) || (flags & DIO_INPUT)) {
/* drive GPIO input from DIO */
GET_GPIO_SEL_REG(g->port, bitnum) = DIO_FUNC(dio);
/* enable digital input */
REG_WRITE_MLV(DIO_CTL_REG(dio), DIO_CTL_IE_MASK,
DIO_CTL_IE_LSB, 1);
}
}
}
int gpio_enable_interrupt(enum gpio_signal signal)

View File

@@ -176,67 +176,19 @@ static inline int x_uart_addr(int ch, int offset)
/*
* Our ARM core doesn't have GPIO alternate functions, but it does have a full
* NxM crossbar called the pinmux, which connects internal peripherals
* including GPIOs to external pins. We'll reuse the alternate function stuff
* from other ECs to configure the pinmux. This requires some clever macros
* that pack both a MUX selector offset (register address) and a MUX selector
* value (which input to choose) into a single uint32_t.
* including GPIOs to external pins.
*/
/* Flags to indicate the direction of the signal-to-pin connection */
/* Flags to indicate the direction and type of the signal-to-pin connection */
#define DIO_INPUT 0x0001
#define DIO_OUTPUT 0x0002
#define DIO_ENABLE_DIRECT_INPUT 0x0004
#define DIO_TO_PERIPHERAL 0x0008
/*
* To store a pinmux DIO in the struct gpio_alt_func's mask field, we use:
*
* bits 31-16: offset of the MUX selector register that drives this signal
* bits 15-0: value to write to any pinmux selector to choose this source
*/
#define DIO(name) (uint32_t)(CONCAT3(GC_PINMUX_DIO, name, _SEL) | \
(CONCAT3(GC_PINMUX_DIO, name, _SEL_OFFSET) << 16))
/* Extract the MUX selector register addres for the DIO */
#define DIO_SEL_REG(word) REG32(GC_PINMUX_BASE_ADDR + \
(((uint32_t)(word) >> 16) & 0xffff))
/* Extract the control register address for this MUX */
#define DIO_CTL_REG(word) REG32(GC_PINMUX_BASE_ADDR + 0x4 + \
(((uint32_t)(word) >> 16) & 0xffff))
/* Extract the selector value to choose this DIO */
#define DIO_FUNC(word) ((uint32_t)(word) & 0xffff)
/*
* The struct gpio_alt_func's port field will either contain an enum
* gpio_signal from gpio_list[], or an internal peripheral function. If bit 31
* is clear, then bits 30-0 are the gpio_signal. If bit 31 is set, the
* peripheral function is packed like the DIO, above.
*
* gpio:
* bit 31: 0
* bit 30-0: enum gpio_signal
*
* peripheral:
* bit 31: 1
* bits 30-16: offset of the MUX selector register that drives this signal
* bits 15-0: value to write to any pinmux selector to choose this source
*/
/* Which is it? */
#define FIELD_IS_FUNC(port) (0x80000000 & (port))
/* Encode a pinmux identifier (both a MUX and a signal name) */
#define GPIO_FUNC(name) (uint32_t)(CONCAT3(GC_PINMUX_, name, _SEL) | \
(CONCAT3(GC_PINMUX_, name, _SEL_OFFSET) << 16) | \
0x80000000)
/* Extract the MUX selector register address to drive this signal */
#define PERIPH_SEL_REG(word) REG32(GC_PINMUX_BASE_ADDR + \
(((uint32_t)(word) >> 16) & 0x7fff))
/* Extract the control register address for this MUX */
#define PERIPH_CTL_REG(word) REG32(GC_PINMUX_BASE_ADDR + 0x4 + \
(((uint32_t)(word) >> 16) & 0x7fff))
/* Extract the selector value to choose this input source */
#define PERIPH_FUNC(word) ((uint32_t)(word) & 0xffff)
/* Extract the GPIO signal */
#define FIELD_GET_GPIO(word) ((uint32_t)(word) & 0x7fffffff)
/* Generate the MUX selector register address for the DIO */
#define DIO_SEL_REG(offset) REG32(GC_PINMUX_BASE_ADDR + offset)
/* Generate the control register address for this MUX */
#define DIO_CTL_REG(offset) REG32(GC_PINMUX_BASE_ADDR + 0x4 + offset)
/* Map a GPIO <port,bitnum> to a selector value or register */
#define GET_GPIO_FUNC(port, bitnum) \