From 7f0f1806e3a474dc15b6bad806b4afa967447774 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 14 Sep 2020 11:01:57 -0400 Subject: [PATCH] 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 Reviewed-by: Simon Glass --- MAINTAINERS | 1 + arch/sandbox/dts/test.dts | 45 ++++- drivers/pinctrl/pinctrl-sandbox.c | 186 ++++++++++++++----- include/dt-bindings/pinctrl/sandbox-pinmux.h | 19 ++ test/dm/Makefile | 3 + test/dm/pinmux.c | 57 ++++++ test/py/tests/test_pinmux.py | 36 ++-- 7 files changed, 274 insertions(+), 73 deletions(-) create mode 100644 include/dt-bindings/pinctrl/sandbox-pinmux.h create mode 100644 test/dm/pinmux.c diff --git a/MAINTAINERS b/MAINTAINERS index ed5e354873..2e53294ed4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -960,6 +960,7 @@ M: Simon Glass S: Maintained F: arch/sandbox/ F: doc/arch/sandbox.rst +F: include/dt-bindings/*/sandbox*.h SH M: Marek Vasut diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index cc372806a0..6ea1073c47 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -2,6 +2,7 @@ #include #include +#include / { 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 = ; bias-pull-down; input-enable; }; gpio3 { - pins = "GPIO3"; + pinmux = ; 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 = , + ; + }; + }; }; hwspinlock@0 { diff --git a/drivers/pinctrl/pinctrl-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c index ac0119d198..d27f74248d 100644 --- a/drivers/pinctrl/pinctrl-sandbox.c +++ b/drivers/pinctrl/pinctrl-sandbox.c @@ -1,57 +1,70 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2015 Masahiro Yamada + * Copyright (C) 2020 Sean Anderson + * Copyright (C) 2015 Masahiro Yamada */ -/* #define DEBUG */ - #include #include -#include #include +#include +#include #include +/* + * 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, }; diff --git a/include/dt-bindings/pinctrl/sandbox-pinmux.h b/include/dt-bindings/pinctrl/sandbox-pinmux.h new file mode 100644 index 0000000000..891af072e5 --- /dev/null +++ b/include/dt-bindings/pinctrl/sandbox-pinmux.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Sean Anderson + */ + +#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 */ diff --git a/test/dm/Makefile b/test/dm/Makefile index 70ba1b6695..e2b0798388 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -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 diff --git a/test/dm/pinmux.c b/test/dm/pinmux.c new file mode 100644 index 0000000000..047184d4bc --- /dev/null +++ b/test/dm/pinmux.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Sean Anderson + */ + +#include +#include +#include +#include +#include + +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); diff --git a/test/py/tests/test_pinmux.py b/test/py/tests/test_pinmux.py index 4e6df992a4..0cbbae000c 100644 --- a/test/py/tests/test_pinmux.py +++ b/test/py/tests/test_pinmux.py @@ -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)