@@ -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";
};
@@ -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:
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.akashi@linaro.org> --- arch/sandbox/dts/test.dts | 115 ++++ drivers/firmware/scmi/sandbox-scmi_agent.c | 722 +++++++++++++++++++++ 2 files changed, 837 insertions(+)