test: pinmux: Add test for pin muxing

This extends the pinctrl-sandbox driver to support pin muxing, and adds a
test for that behaviour. The test is done in C and not python (like the
existing tests for the pinctrl uclass) because it needs to call
pinctrl_select_state.  Another option could be to add a command that
invokes pinctrl_select_state and then test everything in
test/py/tests/test_pinmux.py.

The pinctrl-sandbox driver now mimics the way that many pinmux devices
work.  There are two groups of pins which are muxed together, as well as
four pins which are muxed individually. I have tried to test all normal
paths. However, very few error cases are explicitly checked for.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Sean Anderson 2020-09-14 11:01:57 -04:00 committed by Tom Rini
parent 5eee93e5b1
commit 7f0f1806e3
7 changed files with 274 additions and 73 deletions

View File

@ -960,6 +960,7 @@ M: Simon Glass <sjg@chromium.org>
S: Maintained
F: arch/sandbox/
F: doc/arch/sandbox.rst
F: include/dt-bindings/*/sandbox*.h
SH
M: Marek Vasut <marek.vasut+renesas@gmail.com>

View File

@ -2,6 +2,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/gpio/sandbox-gpio.h>
#include <dt-bindings/pinctrl/sandbox-pinmux.h>
/ {
model = "sandbox";
@ -1094,30 +1095,60 @@
pinctrl {
compatible = "sandbox,pinctrl";
pinctrl-names = "default";
pinctrl-0 = <&gpios>;
pinctrl-names = "default", "alternate";
pinctrl-0 = <&pinctrl_gpios>, <&pinctrl_i2s>;
pinctrl-1 = <&pinctrl_spi>, <&pinctrl_i2c>;
gpios: gpios {
pinctrl_gpios: gpios {
gpio0 {
pins = "GPIO0";
pins = "P5";
function = "GPIO";
bias-pull-up;
input-disable;
};
gpio1 {
pins = "GPIO1";
pins = "P6";
function = "GPIO";
output-high;
drive-open-drain;
};
gpio2 {
pins = "GPIO2";
pinmux = <SANDBOX_PINMUX(7, SANDBOX_PINMUX_GPIO)>;
bias-pull-down;
input-enable;
};
gpio3 {
pins = "GPIO3";
pinmux = <SANDBOX_PINMUX(8, SANDBOX_PINMUX_GPIO)>;
bias-disable;
};
};
pinctrl_i2c: i2c {
groups {
groups = "I2C_UART";
function = "I2C";
};
pins {
pins = "P0", "P1";
drive-open-drain;
};
};
pinctrl_i2s: i2s {
groups = "SPI_I2S";
function = "I2S";
};
pinctrl_spi: spi {
groups = "SPI_I2S";
function = "SPI";
cs {
pinmux = <SANDBOX_PINMUX(5, SANDBOX_PINMUX_CS)>,
<SANDBOX_PINMUX(6, SANDBOX_PINMUX_CS)>;
};
};
};
hwspinlock@0 {

View File

@ -1,57 +1,70 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
* Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*/
/* #define DEBUG */
#include <common.h>
#include <dm.h>
#include <log.h>
#include <dm/pinctrl.h>
#include <dt-bindings/pinctrl/sandbox-pinmux.h>
#include <log.h>
#include <linux/bitops.h>
/*
* This driver emulates a pin controller with the following rules:
* - The pinctrl config for each pin must be set individually
* - The first three pins (P0-P2) must be muxed as a group
* - The next two pins (P3-P4) must be muxed as a group
* - The last four pins (P5-P8) must be muxed individually
*/
static const char * const sandbox_pins[] = {
"SCL",
"SDA",
"TX",
"RX",
"W1",
"GPIO0",
"GPIO1",
"GPIO2",
"GPIO3",
#define PIN(x) \
[x] = "P" #x
PIN(0),
PIN(1),
PIN(2),
PIN(3),
PIN(4),
PIN(5),
PIN(6),
PIN(7),
PIN(8),
#undef PIN
};
static const char * const sandbox_pins_muxing[] = {
"I2C SCL",
"I2C SDA",
"Uart TX",
"Uart RX",
"1-wire gpio",
"gpio",
"gpio",
"gpio",
"gpio",
static const char * const sandbox_pins_muxing[][2] = {
{ "UART TX", "I2C SCL" },
{ "UART RX", "I2C SDA" },
{ "SPI SCLK", "I2S SCK" },
{ "SPI MOSI", "I2S SD" },
{ "SPI MISO", "I2S WS" },
{ "GPIO0", "SPI CS0" },
{ "GPIO1", "SPI CS1" },
{ "GPIO2", "PWM0" },
{ "GPIO3", "PWM1" },
};
#define SANDBOX_GROUP_I2C_UART 0
#define SANDBOX_GROUP_SPI_I2S 1
static const char * const sandbox_groups[] = {
"i2c",
"serial_a",
"serial_b",
"spi",
"w1",
[SANDBOX_GROUP_I2C_UART] = "I2C_UART",
[SANDBOX_GROUP_SPI_I2S] = "SPI_I2S",
};
static const char * const sandbox_functions[] = {
"i2c",
"serial",
"spi",
"w1",
"gpio",
"gpio",
"gpio",
"gpio",
#define FUNC(id) \
[SANDBOX_PINMUX_##id] = #id
FUNC(UART),
FUNC(I2C),
FUNC(SPI),
FUNC(I2S),
FUNC(GPIO),
FUNC(CS),
FUNC(PWM),
#undef FUNC
};
static const struct pinconf_param sandbox_conf_params[] = {
@ -68,9 +81,12 @@ static const struct pinconf_param sandbox_conf_params[] = {
{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
};
/* bitfield used to save param and value of each pin/selector */
static unsigned int sandbox_pins_param[ARRAY_SIZE(sandbox_pins)];
static unsigned int sandbox_pins_value[ARRAY_SIZE(sandbox_pins)];
/* Bitfield used to save param and value of each pin/selector */
struct sandbox_pinctrl_priv {
unsigned int mux;
unsigned int pins_param[ARRAY_SIZE(sandbox_pins)];
unsigned int pins_value[ARRAY_SIZE(sandbox_pins)];
};
static int sandbox_get_pins_count(struct udevice *dev)
{
@ -87,16 +103,18 @@ static int sandbox_get_pin_muxing(struct udevice *dev,
char *buf, int size)
{
const struct pinconf_param *p;
struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
int i;
snprintf(buf, size, "%s", sandbox_pins_muxing[selector]);
snprintf(buf, size, "%s",
sandbox_pins_muxing[selector][!!(priv->mux & BIT(selector))]);
if (sandbox_pins_param[selector]) {
if (priv->pins_param[selector]) {
for (i = 0, p = sandbox_conf_params;
i < ARRAY_SIZE(sandbox_conf_params);
i++, p++) {
if ((sandbox_pins_param[selector] & BIT(p->param)) &&
(!!(sandbox_pins_value[selector] & BIT(p->param)) ==
if ((priv->pins_param[selector] & BIT(p->param)) &&
(!!(priv->pins_value[selector] & BIT(p->param)) ==
p->default_value)) {
strncat(buf, " ", size);
strncat(buf, p->property, size);
@ -133,12 +151,32 @@ static const char *sandbox_get_function_name(struct udevice *dev,
static int sandbox_pinmux_set(struct udevice *dev, unsigned pin_selector,
unsigned func_selector)
{
int mux;
struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
debug("sandbox pinmux: pin = %d (%s), function = %d (%s)\n",
pin_selector, sandbox_get_pin_name(dev, pin_selector),
func_selector, sandbox_get_function_name(dev, func_selector));
sandbox_pins_param[pin_selector] = 0;
sandbox_pins_value[pin_selector] = 0;
if (pin_selector < 5)
return -EINVAL;
switch (func_selector) {
case SANDBOX_PINMUX_GPIO:
mux = 0;
break;
case SANDBOX_PINMUX_CS:
case SANDBOX_PINMUX_PWM:
mux = BIT(pin_selector);
break;
default:
return -EINVAL;
}
priv->mux &= ~BIT(pin_selector);
priv->mux |= mux;
priv->pins_param[pin_selector] = 0;
priv->pins_value[pin_selector] = 0;
return 0;
}
@ -147,25 +185,75 @@ static int sandbox_pinmux_group_set(struct udevice *dev,
unsigned group_selector,
unsigned func_selector)
{
bool mux;
int i, group_start, group_end;
struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
unsigned int mask;
debug("sandbox pinmux: group = %d (%s), function = %d (%s)\n",
group_selector, sandbox_get_group_name(dev, group_selector),
func_selector, sandbox_get_function_name(dev, func_selector));
if (group_selector == SANDBOX_GROUP_I2C_UART) {
group_start = 0;
group_end = 1;
if (func_selector == SANDBOX_PINMUX_UART)
mux = false;
else if (func_selector == SANDBOX_PINMUX_I2C)
mux = true;
else
return -EINVAL;
} else if (group_selector == SANDBOX_GROUP_SPI_I2S) {
group_start = 2;
group_end = 4;
if (func_selector == SANDBOX_PINMUX_SPI)
mux = false;
else if (func_selector == SANDBOX_PINMUX_I2S)
mux = true;
else
return -EINVAL;
} else {
return -EINVAL;
}
mask = GENMASK(group_end, group_start);
priv->mux &= ~mask;
priv->mux |= mux ? mask : 0;
for (i = group_start; i < group_end; i++) {
priv->pins_param[i] = 0;
priv->pins_value[i] = 0;
}
return 0;
}
static int sandbox_pinmux_property_set(struct udevice *dev, u32 pinmux_group)
{
int ret;
unsigned pin_selector = pinmux_group & 0xFFFF;
unsigned func_selector = pinmux_group >> 16;
ret = sandbox_pinmux_set(dev, pin_selector, func_selector);
return ret ? ret : pin_selector;
}
static int sandbox_pinconf_set(struct udevice *dev, unsigned pin_selector,
unsigned param, unsigned argument)
{
struct sandbox_pinctrl_priv *priv = dev_get_priv(dev);
debug("sandbox pinconf: pin = %d (%s), param = %d, arg = %d\n",
pin_selector, sandbox_get_pin_name(dev, pin_selector),
param, argument);
sandbox_pins_param[pin_selector] |= BIT(param);
priv->pins_param[pin_selector] |= BIT(param);
if (argument)
sandbox_pins_value[pin_selector] |= BIT(param);
priv->pins_value[pin_selector] |= BIT(param);
else
sandbox_pins_value[pin_selector] &= ~BIT(param);
priv->pins_value[pin_selector] &= ~BIT(param);
return 0;
}
@ -191,6 +279,7 @@ const struct pinctrl_ops sandbox_pinctrl_ops = {
.get_function_name = sandbox_get_function_name,
.pinmux_set = sandbox_pinmux_set,
.pinmux_group_set = sandbox_pinmux_group_set,
.pinmux_property_set = sandbox_pinmux_property_set,
.pinconf_num_params = ARRAY_SIZE(sandbox_conf_params),
.pinconf_params = sandbox_conf_params,
.pinconf_set = sandbox_pinconf_set,
@ -207,5 +296,6 @@ U_BOOT_DRIVER(sandbox_pinctrl) = {
.name = "sandbox_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = sandbox_pinctrl_match,
.priv_auto_alloc_size = sizeof(struct sandbox_pinctrl_priv),
.ops = &sandbox_pinctrl_ops,
};

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
*/
#ifndef SANDBOX_PINMUX_H
#define SANDBOX_PINMUX_H
#define SANDBOX_PINMUX_UART 0
#define SANDBOX_PINMUX_I2C 1
#define SANDBOX_PINMUX_SPI 2
#define SANDBOX_PINMUX_I2S 3
#define SANDBOX_PINMUX_GPIO 4
#define SANDBOX_PINMUX_CS 5
#define SANDBOX_PINMUX_PWM 6
#define SANDBOX_PINMUX(pin, func) ((func) << 16 | (pin))
#endif /* SANDBOX_PINMUX_H */

View File

@ -81,4 +81,7 @@ obj-$(CONFIG_CLK_K210_SET_RATE) += k210_pll.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o
obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o
ifneq ($(CONFIG_PINMUX),)
obj-$(CONFIG_PINCONF) += pinmux.o
endif
endif

57
test/dm/pinmux.c Normal file
View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
*/
#include <common.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <dm/test.h>
#include <test/ut.h>
static int dm_test_pinmux(struct unit_test_state *uts)
{
char buf[64];
struct udevice *dev;
#define test_muxing(selector, expected) do { \
ut_assertok(pinctrl_get_pin_muxing(dev, selector, buf, sizeof(buf))); \
ut_asserteq_str(expected, (char *)&buf); \
} while (0)
ut_assertok(uclass_get_device_by_name(UCLASS_PINCTRL, "pinctrl", &dev));
test_muxing(0, "UART TX.");
test_muxing(1, "UART RX.");
test_muxing(2, "I2S SCK.");
test_muxing(3, "I2S SD.");
test_muxing(4, "I2S WS.");
test_muxing(5, "GPIO0 bias-pull-up input-disable.");
test_muxing(6, "GPIO1 drive-open-drain.");
test_muxing(7, "GPIO2 bias-pull-down input-enable.");
test_muxing(8, "GPIO3 bias-disable.");
ut_assertok(pinctrl_select_state(dev, "alternate"));
test_muxing(0, "I2C SCL drive-open-drain.");
test_muxing(1, "I2C SDA drive-open-drain.");
test_muxing(2, "SPI SCLK.");
test_muxing(3, "SPI MOSI.");
test_muxing(4, "SPI MISO.");
test_muxing(5, "SPI CS0.");
test_muxing(6, "SPI CS1.");
test_muxing(7, "GPIO2 bias-pull-down input-enable.");
test_muxing(8, "GPIO3 bias-disable.");
ut_assertok(pinctrl_select_state(dev, "0"));
test_muxing(0, "I2C SCL drive-open-drain.");
test_muxing(1, "I2C SDA drive-open-drain.");
test_muxing(2, "I2S SCK.");
test_muxing(3, "I2S SD.");
test_muxing(4, "I2S WS.");
test_muxing(5, "GPIO0 bias-pull-up input-disable.");
test_muxing(6, "GPIO1 drive-open-drain.");
test_muxing(7, "GPIO2 bias-pull-down input-enable.");
test_muxing(8, "GPIO3 bias-disable.");
return 0;
}
DM_TEST(dm_test_pinmux, UT_TESTF_SCAN_FDT);

View File

@ -28,15 +28,15 @@ def test_pinmux_status_all(u_boot_console):
assert ('a6 : gpio output .' in output)
assert ('pinctrl:' in output)
assert ('SCL : I2C SCL.' in output)
assert ('SDA : I2C SDA.' in output)
assert ('TX : Uart TX.' in output)
assert ('RX : Uart RX.' in output)
assert ('W1 : 1-wire gpio.' in output)
assert ('GPIO0 : gpio bias-pull-up input-disable.' in output)
assert ('GPIO1 : gpio drive-open-drain.' in output)
assert ('GPIO2 : gpio bias-pull-down input-enable.' in output)
assert ('GPIO3 : gpio bias-disable.' in output)
assert ('P0 : UART TX.' in output)
assert ('P1 : UART RX.' in output)
assert ('P2 : I2S SCK.' in output)
assert ('P3 : I2S SD.' in output)
assert ('P4 : I2S WS.' in output)
assert ('P5 : GPIO0 bias-pull-up input-disable.' in output)
assert ('P6 : GPIO1 drive-open-drain.' in output)
assert ('P7 : GPIO2 bias-pull-down input-enable.' in output)
assert ('P8 : GPIO3 bias-disable.' in output)
@pytest.mark.buildconfigspec('cmd_pinmux')
@pytest.mark.boardspec('sandbox')
@ -73,12 +73,12 @@ def test_pinmux_status(u_boot_console):
assert (not 'pinctrl-gpio:' in output)
assert (not 'pinctrl:' in output)
assert ('SCL : I2C SCL.' in output)
assert ('SDA : I2C SDA.' in output)
assert ('TX : Uart TX.' in output)
assert ('RX : Uart RX.' in output)
assert ('W1 : 1-wire gpio.' in output)
assert ('GPIO0 : gpio bias-pull-up input-disable.' in output)
assert ('GPIO1 : gpio drive-open-drain.' in output)
assert ('GPIO2 : gpio bias-pull-down input-enable.' in output)
assert ('GPIO3 : gpio bias-disable.' in output)
assert ('P0 : UART TX.' in output)
assert ('P1 : UART RX.' in output)
assert ('P2 : I2S SCK.' in output)
assert ('P3 : I2S SD.' in output)
assert ('P4 : I2S WS.' in output)
assert ('P5 : GPIO0 bias-pull-up input-disable.' in output)
assert ('P6 : GPIO1 drive-open-drain.' in output)
assert ('P7 : GPIO2 bias-pull-down input-enable.' in output)
assert ('P8 : GPIO3 bias-disable.' in output)