With this patch, sandbox SCMI agent can handle pinctrl protocol. This feature is used in an unit test for SCMI pinctrl.
Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org> --- arch/sandbox/dts/test.dts | 115 ++++ drivers/firmware/scmi/sandbox-scmi_agent.c | 722 +++++++++++++++++++++ 2 files changed, 837 insertions(+) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index dc0bfdfb6e4b..d2ddea801995 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -723,9 +723,124 @@ }; }; }; + + pinctrl_scmi: protocol@19 { + reg = <0x19>; + + pinctrl-names = "default","alternate"; + pinctrl-0 = <&scmi_pinctrl_gpios>, <&scmi_pinctrl_i2s>; + pinctrl-1 = <&scmi_pinctrl_spi>, <&scmi_pinctrl_i2c>; + +#if 0 + scmi_pinctrl_gpio_a: scmi_gpios { + gpio-controller; + #gpio-cells = <2>; + gpio-bank-name = "scmi_gpios"; + ngpios = <4>; + gpio-ranges = <&pinctrl_scmi 0 5 4>, + <&pinctrl_scmi 4 0 0>; + gpio-ranges-group-names = "", + "GPIO_B"; + + hog_input_1 { + gpio-hog; + input; + gpios = <1 GPIO_ACTIVE_HIGH>; + }; + hog_output_3 { + gpio-hog; + output-high; + output-mode; + output-value = <1>; + gpios = <3 GPIO_ACTIVE_HIGH>; + }; + }; +#endif + + scmi_pinctrl_gpios: gpios-pins { + gpio0 { + pins = "P5"; + function = "GPIO"; + bias-pull-up; + // input-disable; + input-mode = <0>; + }; + gpio1 { + pins = "P6"; + function = "GPIO"; + // output-high; + output-mode; + output-value = <1>; + drive-open-drain; + }; + gpio2 { + pinmux = <SANDBOX_PINMUX(7, SANDBOX_PINMUX_GPIO)>; + bias-pull-down; + // input-enable; + input-mode; + }; + gpio3 { + pinmux = <SANDBOX_PINMUX(8, SANDBOX_PINMUX_GPIO)>; + bias-disable; + }; + }; + + scmi_pinctrl_i2c: i2c-pins { + groups { + groups = "I2C_UART"; + function = "I2C"; + }; + + pins { + pins = "P0", "P1"; + drive-open-drain; + }; + }; + + scmi_pinctrl_i2s: i2s-pins { + groups = "SPI_I2S"; + function = "I2S"; + }; + + scmi_pinctrl_spi: spi-pins { + groups = "SPI_I2S"; + function = "SPI"; + + cs { + pinmux = <SANDBOX_PINMUX(5, SANDBOX_PINMUX_CS)>, + <SANDBOX_PINMUX(6, SANDBOX_PINMUX_CS)>; + }; + }; + }; }; }; +#if 1 + scmi_pinctrl_gpio_a: scmi_gpios { + compatible = "arm,scmi-gpio-generic"; + gpio-controller; + #gpio-cells = <2>; + gpio-bank-name = "scmi_gpios"; + gpio-ranges = <&pinctrl_scmi 0 5 4>, + <&pinctrl_scmi 4 0 0>; + gpio-ranges-group-names = "", + "GPIO_B"; + + hog_input_1 { + gpio-hog; + input; + gpios = <1 GPIO_ACTIVE_HIGH>; + }; + hog_output_3 { + gpio-hog; + output-high; + output-mode; + output-value = <1>; + gpios = <3 GPIO_ACTIVE_HIGH>; + }; + }; +#endif + fpga { compatible = "sandbox,fpga"; }; diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 27d17809be43..d5ff8a2b1c79 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -14,6 +14,7 @@ #include <asm/io.h> #include <asm/scmi_test.h> #include <dm/device_compat.h> +#include <dt-bindings/pinctrl/sandbox-pinmux.h> #include <linux/bitfield.h> #include <linux/kernel.h> @@ -43,8 +44,11 @@ #define SANDBOX_SCMI_AGENT_NAME "OSPM" #define SANDBOX_SCMI_PLATFORM_NAME "platform" +#define SANDBOX_SCMI_PIN_CONTROL_PROTOCOL_VERSION SCMI_PIN_CONTROL_PROTOCOL_VERSION + static u8 protocols[] = { SCMI_PROTOCOL_ID_CLOCK, + SCMI_PROTOCOL_ID_PIN_CONTROL, SCMI_PROTOCOL_ID_RESET_DOMAIN, SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN, }; @@ -796,6 +800,696 @@ static int sandbox_scmi_voltd_level_get(struct udevice *dev, return 0; } +/* Pin control protocol */ + +/* + * This driver emulates a pin controller with the following rules: + * - The pinctrl config for each pin must be set individually + * - The first two pins (P0-P1) must be muxed as a group + * - The next three pins (P2-P4) must be muxed as a group + * - The next four pins (P5-P8) must be muxed individually + * - The last two pins (P9-P10) must be fixed as a GPIO group only + + P0: "UART TX", "I2C SCL" + P1: "UART RX", "I2C SDA" + P2: "SPI SCLK", "I2S SCK" + P3: "SPI MOSI", "I2S SD" + P4: "SPI MISO", "I2S WS" + P5: "GPIO0", "SPI CS0" + P6: "GPIO1", "SPI CS1" + P7: "GPIO2", "PWM0" + P8: "GPIO3", "PWM1" + P9: "GPIO_B" + P10: "GPIO_B" + + */ + +static const char * const sandbox_pins[] = { +#define PIN(x) \ + [x] = "P" #x + PIN(0), + PIN(1), + PIN(2), + PIN(3), + PIN(4), + PIN(5), + PIN(6), + PIN(7), + PIN(8), + PIN(9), + PIN(10), +#undef PIN +}; + +static unsigned int sandbox_pin_functions[9]; +static u32 sandbox_pin_states[9][SCMI_PINCTRL_CONFIG_RESERVED]; + +#define SANDBOX_GROUP_I2C_UART 0 +#define SANDBOX_GROUP_SPI_I2S 1 +#define SANDBOX_GROUP_GPIO_B 2 + +static const char * const sandbox_groups[] = { + /* P0-P1 */ + [SANDBOX_GROUP_I2C_UART] = "I2C_UART", + /* P2-P4 */ + [SANDBOX_GROUP_SPI_I2S] = "SPI_I2S", + /* P9-P10 */ + [SANDBOX_GROUP_GPIO_B] = "GPIO_B", +}; + +static const char * const sandbox_functions[] = { +#define FUNC(id) \ + [SANDBOX_PINMUX_##id] = #id + FUNC(UART), + FUNC(I2C), + FUNC(SPI), + FUNC(I2S), + FUNC(GPIO), + FUNC(CS), + FUNC(PWM), + /* FUNC(GPIO_B) */ +#undef FUNC +}; + +static int sandbox_scmi_pinctrl_protocol_version(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_protocol_version_out *out = NULL; + + if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + out = (struct scmi_protocol_version_out *)msg->out_msg; + out->version = SANDBOX_SCMI_PIN_CONTROL_PROTOCOL_VERSION; + out->status = SCMI_SUCCESS; + + return 0; +} + +static int sandbox_scmi_pinctrl_protocol_attrs(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_protocol_attrs_out *out = NULL; + + if (!msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + out = (struct scmi_pinctrl_protocol_attrs_out *)msg->out_msg; + out->attributes_low = (ARRAY_SIZE(sandbox_groups) << 16) + + ARRAY_SIZE(sandbox_pins); + out->attributes_high = ARRAY_SIZE(sandbox_functions); + out->status = SCMI_SUCCESS; + + return 0; +} + +static int sandbox_scmi_pinctrl_attrs(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_attrs_in *in; + struct scmi_pinctrl_attrs_out *out; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_pinctrl_attrs_in *)msg->in_msg; + out = (struct scmi_pinctrl_attrs_out *)msg->out_msg; + + /* + * Currently all pins have a name with less than 16 characters + * (SCMI_PINCTRL_NAME_LENGTH_MAX). + */ + switch (SCMI_PINCTRL_TYPE(in->flags)) { + case SCMI_PINCTRL_TYPE_PIN: + if (in->id < ARRAY_SIZE(sandbox_pins)) { + strcpy(out->name, sandbox_pins[in->id]); + out->attributes = 0; + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + break; + case SCMI_PINCTRL_TYPE_GROUP: + if (in->id < ARRAY_SIZE(sandbox_groups)) { + strcpy(out->name, sandbox_groups[in->id]); + out->attributes = in->id ? 3 : 2; + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + break; + case SCMI_PINCTRL_TYPE_FUNCTION: + if (in->id < ARRAY_SIZE(sandbox_functions)) { + strcpy(out->name, sandbox_functions[in->id]); + if (in->id == 4) /* UART */ + out->attributes = 4; + else if (in->id == 5 || in->id == 6) /* CS or PWM */ + out->attributes = 2; + else + out->attributes = 1; + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + break; + default: + out->status = SCMI_INVALID_PARAMETERS; + goto err; + } + + out->status = SCMI_SUCCESS; + +err: + return 0; +} + +static int sandbox_scmi_pinctrl_list_assocs(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_list_assocs_in *in; + struct scmi_pinctrl_list_assocs_out *out; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_pinctrl_list_assocs_in *)msg->in_msg; + out = (struct scmi_pinctrl_list_assocs_out *)msg->out_msg; + + /* + * UART -> GROUP0 + * I2C -> GROUP0 + * SPI -> GROUP1 + * I2S -> GROUP1 + * GPIO -> PIN5, 6, 7, 8 + * CS -> PIN5, 6 + * PWM -> PIN7, 8 + * (GPIO_B -> GROUP2) + */ + switch (SCMI_PINCTRL_TYPE(in->flags)) { + case SCMI_PINCTRL_TYPE_GROUP: + if (in->id == SANDBOX_GROUP_I2C_UART) { + if (in->index == 0) { + out->array[0] = 0; + out->array[1] = 1; + out->flags = 2; + } else if (in->index == 1) { + out->array[0] = 0; + out->flags = 1; + } else { + out->status = SCMI_OUT_OF_RANGE; + goto err; + } + } else if (in->id == SANDBOX_GROUP_SPI_I2S) { + if (in->index == 0) { + out->array[0] = 2; + out->array[1] = 3; + out->array[2] = 4; + out->flags = 3; + } else if (in->index == 1) { + out->array[0] = 3; + out->array[1] = 4; + out->flags = 2; + } else if (in->index == 2) { + out->array[0] = 4; + out->flags = 1; + } else { + out->status = SCMI_OUT_OF_RANGE; + goto err; + } + } else if (in->id == SANDBOX_GROUP_GPIO_B) { + if (in->index == 0) { + out->array[0] = 9; + out->array[1] = 10; + out->flags = 2; + } else if (in->index == 1) { + out->array[0] = 10; + out->flags = 1; + } else { + out->status = SCMI_OUT_OF_RANGE; + goto err; + } + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + break; + case SCMI_PINCTRL_TYPE_FUNCTION: + if (in->id == SANDBOX_PINMUX_UART) { + if (in->index > 0) { + out->status = SCMI_OUT_OF_RANGE; + goto err; + } + out->array[0] = SANDBOX_GROUP_I2C_UART; + out->flags = 1; + } else if (in->id == SANDBOX_PINMUX_I2C) { + if (in->index > 0) { + out->status = SCMI_OUT_OF_RANGE; + goto err; + } + out->array[0] = SANDBOX_GROUP_I2C_UART; + out->flags = 1; + } else if (in->id == SANDBOX_PINMUX_SPI) { + if (in->index > 0) { + out->status = SCMI_OUT_OF_RANGE; + goto err; + } + out->array[0] = SANDBOX_GROUP_SPI_I2S; + out->flags = 1; + } else if (in->id == SANDBOX_PINMUX_I2S) { + if (in->index > 0) { + out->status = SCMI_OUT_OF_RANGE; + goto err; + } + out->array[0] = SANDBOX_GROUP_SPI_I2S; + out->flags = 1; + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + break; + default: + out->status = SCMI_INVALID_PARAMETERS; + goto err; + } + + out->status = SCMI_SUCCESS; + +err: + return 0; +} + +static void copy_config(struct scmi_pin_entry *configs, u32 selector, int skip, + u32 *num, u32 *remaining) +{ + int max_num, i; + + if ((skip + SCMI_PINCTRL_CONFIG_ENTRY_MAX) + > SCMI_PINCTRL_CONFIG_RESERVED) + max_num = SCMI_PINCTRL_CONFIG_RESERVED - skip; + else + max_num = SCMI_PINCTRL_CONFIG_ENTRY_MAX; + + /* TODO: eliminate disabled properties? */ + for (i = 0; i < max_num; i++) { + configs[i].type = skip + i; + configs[i].value = sandbox_pin_states[selector][skip + i]; + } + + *num = max_num; + *remaining = SCMI_PINCTRL_CONFIG_RESERVED - (skip + max_num); +} + +static int sandbox_scmi_pinctrl_config_get(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_config_get_in *in; + struct scmi_pinctrl_config_get_out *out; + u32 type, num, remaining; + int all_configs, skip; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_pinctrl_config_get_in *)msg->in_msg; + out = (struct scmi_pinctrl_config_get_out *)msg->out_msg; + + all_configs = in->attributes & SCMI_PINCTRL_CONFIG_GET_ALL; + skip = SCMI_PINCTRL_CONFIG_GET_SKIP(in->attributes); + type = SCMI_PINCTRL_CONFIG_GET_TYPE(in->attributes); + if (type >= SCMI_PINCTRL_CONFIG_RESERVED) { + out->status = SCMI_INVALID_PARAMETERS; + goto err; + } + + switch (SCMI_PINCTRL_CONFIG_GET_PINCTRL_TYPE(in->attributes)) { + case SCMI_PINCTRL_TYPE_PIN: + if (in->id < ARRAY_SIZE(sandbox_pins)) { + if (all_configs) { + if (skip >= SCMI_PINCTRL_CONFIG_RESERVED) { + out->status = SCMI_INVALID_PARAMETERS; + goto err; + } + num = 0; /* avoid compiler warning */ + remaining = 0; + copy_config(&out->configs[0], in->id, skip, + &num, &remaining); + } else { + out->configs[0].type = type; + out->configs[0].value = + sandbox_pin_states[in->id][type]; + num = 1; + remaining = 0; + } + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + out->num_configs = + SCMI_PINCTRL_CONFIG_GET_NUM_CONFIGS(remaining, num); + break; + case SCMI_PINCTRL_TYPE_GROUP: + if (in->id < ARRAY_SIZE(sandbox_groups)) { + /* TODO */; + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + break; + default: + out->status = SCMI_INVALID_PARAMETERS; + goto err; + } + + out->status = SCMI_SUCCESS; + +err: + return 0; +} + +static int sandbox_scmi_pinctrl_config_set(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_config_set_in *in; + u32 *status; + int i, num; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL; + + in = (struct scmi_pinctrl_config_set_in *)msg->in_msg; + status = (u32 *)msg->out_msg; + + num = SCMI_PINCTRL_CONFIG_SET_NUM_CONFIGS(in->attributes); + if (num > SCMI_PINCTRL_CONFIG_ENTRY_MAX) { + *status = SCMI_PROTOCOL_ERROR; + goto err; + } + + switch (SCMI_PINCTRL_CONFIG_SET_PINCTRL_TYPE(in->attributes)) { + case SCMI_PINCTRL_TYPE_PIN: + if (in->id < ARRAY_SIZE(sandbox_pins)) { + /* TODO: check value range */ + for (i = 0; i < num; i++) + sandbox_pin_states[in->id][in->configs[i].type] + = in->configs[i].value; + } else { + *status = SCMI_NOT_FOUND; + goto err; + } + break; + case SCMI_PINCTRL_TYPE_GROUP: + /* TODO: check value range */ + if (!in->id) { + for (i = 0; i < num; i++) { + sandbox_pin_states[0][in->configs[i].type] = + in->configs[i].value; + sandbox_pin_states[1][in->configs[i].type] = + in->configs[i].value; + } + } else if (in->id == 1) { + for (i = 0; i < num; i++) { + sandbox_pin_states[2][in->configs[i].type] = + in->configs[i].value; + sandbox_pin_states[3][in->configs[i].type] = + in->configs[i].value; + sandbox_pin_states[4][in->configs[i].type] = + in->configs[i].value; + } + } else if (in->id == 2) { + for (i = 0; i < num; i++) { + sandbox_pin_states[9][in->configs[i].type] = + in->configs[i].value; + sandbox_pin_states[10][in->configs[i].type] = + in->configs[i].value; + } + } else { + *status = SCMI_NOT_FOUND; + goto err; + } + break; + default: + *status = SCMI_INVALID_PARAMETERS; + goto err; + } + + *status = SCMI_SUCCESS; +err: + return 0; +} + +static int sandbox_scmi_pinctrl_function_select(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_function_select_in *in; + u32 *status; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL; + + in = (struct scmi_pinctrl_function_select_in *)msg->in_msg; + status = (u32 *)msg->out_msg; + + switch (SCMI_PINCTRL_TYPE(in->flags)) { + case SCMI_PINCTRL_TYPE_PIN: + if (in->id == 5 || in->id == 6) { + if (in->function_id == SANDBOX_PINMUX_GPIO || + in->function_id == SANDBOX_PINMUX_CS) { + sandbox_pin_functions[in->id] = in->function_id; + *status = SCMI_SUCCESS; + } else { + *status = SCMI_NOT_SUPPORTED; + } + } else if (in->id == 7 || in->id == 8) { + if (in->function_id == SANDBOX_PINMUX_GPIO || + in->function_id == SANDBOX_PINMUX_PWM) { + sandbox_pin_functions[in->id] = in->function_id; + *status = SCMI_SUCCESS; + } else { + *status = SCMI_NOT_SUPPORTED; + } + } + break; + case SCMI_PINCTRL_TYPE_GROUP: + if (in->id == SANDBOX_GROUP_I2C_UART) { + if (in->function_id == SANDBOX_PINMUX_UART || + in->function_id == SANDBOX_PINMUX_I2C) { + sandbox_pin_functions[0] = in->function_id; + sandbox_pin_functions[1] = in->function_id; + *status = SCMI_SUCCESS; + } else { + *status = SCMI_NOT_SUPPORTED; + } + } else if (in->id == SANDBOX_GROUP_SPI_I2S) { + if (in->function_id == SANDBOX_PINMUX_SPI || + in->function_id == SANDBOX_PINMUX_I2S) { + sandbox_pin_functions[2] = in->function_id; + sandbox_pin_functions[3] = in->function_id; + sandbox_pin_functions[4] = in->function_id; + *status = SCMI_SUCCESS; + } else { + *status = SCMI_NOT_SUPPORTED; + } + } + break; + default: + *status = SCMI_INVALID_PARAMETERS; + goto err; + } + + *status = SCMI_SUCCESS; +err: + return 0; +} + +static int sandbox_scmi_pinctrl_request(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_request_in *in; + u32 *status; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL; + + in = (struct scmi_pinctrl_request_in *)msg->in_msg; + status = (u32 *)msg->out_msg; + + /* + * No other agent, so always accept the request + */ + switch (SCMI_PINCTRL_TYPE(in->flags)) { + case SCMI_PINCTRL_TYPE_PIN: + if (in->id >= ARRAY_SIZE(sandbox_pins)) { + *status = SCMI_NOT_FOUND; + goto err; + } + break; + case SCMI_PINCTRL_TYPE_GROUP: + if (in->id >= ARRAY_SIZE(sandbox_groups)) { + *status = SCMI_NOT_FOUND; + goto err; + } + break; + default: + *status = SCMI_INVALID_PARAMETERS; + goto err; + } + + *status = SCMI_SUCCESS; +err: + return 0; +} + +static int sandbox_scmi_pinctrl_release(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_release_in *in; + u32 *status; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL; + + in = (struct scmi_pinctrl_release_in *)msg->in_msg; + status = (u32 *)msg->out_msg; + + /* + * No other agent, so always accept the release + */ + switch (SCMI_PINCTRL_TYPE(in->flags)) { + case SCMI_PINCTRL_TYPE_PIN: + if (in->id >= ARRAY_SIZE(sandbox_pins)) { + *status = SCMI_NOT_FOUND; + goto err; + } + break; + case SCMI_PINCTRL_TYPE_GROUP: + if (in->id >= ARRAY_SIZE(sandbox_groups)) { + *status = SCMI_NOT_FOUND; + goto err; + } + break; + default: + *status = SCMI_INVALID_PARAMETERS; + goto err; + } + + *status = SCMI_SUCCESS; +err: + return 0; +} + +static int sandbox_scmi_pinctrl_name_get(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_name_get_in *in; + struct scmi_pinctrl_name_get_out *out; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*out)) + return -EINVAL; + + in = (struct scmi_pinctrl_name_get_in *)msg->in_msg; + out = (struct scmi_pinctrl_name_get_out *)msg->out_msg; + + /* + * Currently all pins have a name with less than 64 characters + */ + switch (SCMI_PINCTRL_TYPE(in->flags)) { + case SCMI_PINCTRL_TYPE_PIN: + if (in->id < ARRAY_SIZE(sandbox_pins)) { + strcpy(out->name, sandbox_pins[in->id]); + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + break; + case SCMI_PINCTRL_TYPE_GROUP: + if (in->id < ARRAY_SIZE(sandbox_groups)) { + strcpy(out->name, sandbox_groups[in->id]); + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + break; + case SCMI_PINCTRL_TYPE_FUNCTION: + if (in->id < ARRAY_SIZE(sandbox_functions)) { + strcpy(out->name, sandbox_functions[in->id]); + } else { + out->status = SCMI_NOT_FOUND; + goto err; + } + break; + default: + out->status = SCMI_INVALID_PARAMETERS; + goto err; + } + + out->flags = 0; + out->status = SCMI_SUCCESS; + +err: + return 0; +} + +static int sandbox_scmi_pinctrl_set_permissions(struct udevice *dev, + struct scmi_msg *msg) +{ + struct scmi_pinctrl_set_permissions_in *in; + u32 *status; + + if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) || + !msg->out_msg || msg->out_msg_sz < sizeof(*status)) + return -EINVAL; + + in = (struct scmi_pinctrl_set_permissions_in *)msg->in_msg; + status = (u32 *)msg->out_msg; + + if (in->agent_id != 1) { + *status = SCMI_NOT_FOUND; + goto err; + } + + switch (SCMI_PINCTRL_TYPE(in->flags)) { + case SCMI_PINCTRL_TYPE_PIN: + if (in->id < ARRAY_SIZE(sandbox_pins)) { + if (in->flags & SCMI_PINCTRL_PERMISSION) + *status = SCMI_SUCCESS; + else + /* unset not allowed */ + *status = SCMI_DENIED; + } else { + *status = SCMI_NOT_FOUND; + goto err; + } + break; + case SCMI_PINCTRL_TYPE_GROUP: + if (in->id < ARRAY_SIZE(sandbox_groups)) { + if (in->flags & SCMI_PINCTRL_PERMISSION) + *status = SCMI_SUCCESS; + else + /* unset not allowed */ + *status = SCMI_DENIED; + } else { + *status = SCMI_NOT_FOUND; + goto err; + } + break; + default: + *status = SCMI_INVALID_PARAMETERS; + goto err; + } + + *status = SCMI_SUCCESS; +err: + return 0; +} + static int sandbox_scmi_test_process_msg(struct udevice *dev, struct scmi_channel *channel, struct scmi_msg *msg) @@ -847,6 +1541,34 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev, break; } break; + case SCMI_PROTOCOL_ID_PIN_CONTROL: + switch (msg->message_id) { + case SCMI_PROTOCOL_VERSION: + return sandbox_scmi_pinctrl_protocol_version(dev, msg); + case SCMI_PROTOCOL_ATTRIBUTES: + return sandbox_scmi_pinctrl_protocol_attrs(dev, msg); + case SCMI_PINCTRL_ATTRIBUTES: + return sandbox_scmi_pinctrl_attrs(dev, msg); + case SCMI_PINCTRL_LIST_ASSOCIATIONS: + return sandbox_scmi_pinctrl_list_assocs(dev, msg); + case SCMI_PINCTRL_CONFIG_GET: + return sandbox_scmi_pinctrl_config_get(dev, msg); + case SCMI_PINCTRL_CONFIG_SET: + return sandbox_scmi_pinctrl_config_set(dev, msg); + case SCMI_PINCTRL_FUNCTION_SELECT: + return sandbox_scmi_pinctrl_function_select(dev, msg); + case SCMI_PINCTRL_REQUEST: + return sandbox_scmi_pinctrl_request(dev, msg); + case SCMI_PINCTRL_RELEASE: + return sandbox_scmi_pinctrl_release(dev, msg); + case SCMI_PINCTRL_NAME_GET: + return sandbox_scmi_pinctrl_name_get(dev, msg); + case SCMI_PINCTRL_SET_PERMISSIONS: + return sandbox_scmi_pinctrl_set_permissions(dev, msg); + default: + break; + } + break; case SCMI_PROTOCOL_ID_RESET_DOMAIN: switch (msg->message_id) { case SCMI_RESET_DOMAIN_ATTRIBUTES: -- 2.34.1