diff --git a/examples/BUILD b/examples/BUILD index 97b393b..f92b9e7 100644 --- a/examples/BUILD +++ b/examples/BUILD @@ -243,6 +243,7 @@ cc_binary( "//protocol:authz_record", "//protocol:chipinfo", "//protocol:console", + "//protocol:gpio_drive_strength", "//protocol:controlled_storage", "//protocol:dfu_check", "//protocol:dfu_hostcmd", diff --git a/examples/htool.c b/examples/htool.c index 22ec4c7..ef3120a 100644 --- a/examples/htool.c +++ b/examples/htool.c @@ -60,6 +60,7 @@ #include "protocol/chipinfo.h" #include "protocol/console.h" #include "protocol/controlled_storage.h" +#include "protocol/gpio_drive_strength.h" #include "protocol/hello.h" #include "protocol/opentitan_version.h" #include "protocol/progress.h" @@ -759,6 +760,50 @@ int htool_controlled_storage_delete(const struct htool_invocation* inv) { return libhoth_controlled_storage_delete(dev, slot); } +static int command_set_gpio_drive_strength(const struct htool_invocation* inv) { + struct libhoth_device* dev = htool_libhoth_device(); + if (!dev) { + return -1; + } + + uint32_t strength; + if (htool_get_param_u32(inv, "strength", &strength)) { + return -1; + } + + if (strength > MAX_GPIO_DRIVE_STRENGTH) { + fprintf(stderr, "Drive strength can only be up to 15.\n"); + return -1; + } + + bool has_dio = htool_has_param(inv, "dio"); + bool has_mio = htool_has_param(inv, "mio"); + + if (!has_dio && !has_mio) { + fprintf(stderr, "Must specify either --dio or --mio.\n"); + return -1; + } + + if (has_dio && has_mio) { + fprintf(stderr, "Cannot specify both --dio and --mio.\n"); + return -1; + } + + uint32_t pad; + if (has_dio) { + if (htool_get_param_u32(inv, "dio", &pad)) { + return -1; + } + pad += LIBHOTH_GPIO_DIO_PAD_OFFSET; + } else { + if (htool_get_param_u32(inv, "mio", &pad)) { + return -1; + } + } + + return libhoth_set_gpio_drive_strength(dev, (uint8_t)pad, (uint8_t)strength); +} + static int command_hello(const struct htool_invocation* inv) { struct libhoth_device* dev = htool_libhoth_device(); if (!dev) { @@ -1565,6 +1610,39 @@ static const struct htool_cmd CMDS[] = { {}}, .func = htool_controlled_storage_delete, }, + { + .verbs = (const char*[]){"gpio", "set_drive_strength", NULL}, + .desc = "Set GPIO drive strength", + .params = + (const struct htool_param[]){ + {.type = HTOOL_FLAG_VALUE, + .ch = 's', + .name = "strength", + .default_value = NULL, + .desc = "The drive strength to set from 0 - 15"}, + {.type = HTOOL_FLAG_VALUE, + .ch = 'd', + .name = "dio", + .default_value = NULL, + .desc = "Configure the DIO pad with the given index. Values " + "are:\n" + " (0 => USB_DP | 1 => USB_DN | 2-5 => " + "SPI_HOST0_D0-3 |\n" + " 6-9 => SPI_DEV_D0-3 | 12 => SPI_DEV_CLK | " + "13 => SPI_DEV_CSB |\n" + " 14 => SPI_HOST0_CLK | 15 => " + "SPI_HOST0_CSB)."}, + {.type = HTOOL_FLAG_VALUE, + .ch = 'm', + .name = "mio", + .default_value = NULL, + .desc = "Configure the MIO pad with the given index. Values " + "are:\n" + " (0-8 => IOA0-8 | 9-21 => IOB0-12 | 22-34 " + "=> IOC0-12 | 35-46 => IOR0-13)."}, + {}}, + .func = command_set_gpio_drive_strength, + }, { .verbs = (const char*[]){"hello", NULL}, .desc = "A test function to send and receive an integer", diff --git a/protocol/BUILD b/protocol/BUILD index 3c15d63..e2b9747 100644 --- a/protocol/BUILD +++ b/protocol/BUILD @@ -406,6 +406,28 @@ cc_test( ], ) +cc_library( + name = "gpio_drive_strength", + srcs = ["gpio_drive_strength.c"], + hdrs = ["gpio_drive_strength.h"], + deps = [ + ":host_cmd", + "//transports:libhoth_device", + ], +) + +cc_test( + name = "gpio_drive_strength_test", + srcs = ["gpio_drive_strength_test.cc"], + deps = [ + ":gpio_drive_strength", + "//protocol/test:libhoth_device_mock", + "//transports:libhoth_device", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + cc_library( name = "opentitan_version", srcs = ["opentitan_version.c"], diff --git a/protocol/gpio_drive_strength.c b/protocol/gpio_drive_strength.c new file mode 100644 index 0000000..ac3845a --- /dev/null +++ b/protocol/gpio_drive_strength.c @@ -0,0 +1,31 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "protocol/gpio_drive_strength.h" + +#include +#include + +#include "protocol/host_cmd.h" + +int libhoth_set_gpio_drive_strength(struct libhoth_device* const dev, + const uint8_t pad, const uint8_t strength) { + const struct hoth_request_set_gpio_drive_strength request = { + .pad = pad, + .strength = strength, + }; + return libhoth_hostcmd_exec(dev, HOTH_CMD_SET_GPIO_DRIVE_STRENGTH, + /*version=*/0, &request, sizeof(request), + /*response=*/NULL, /*response_size=*/0, NULL); +} diff --git a/protocol/gpio_drive_strength.h b/protocol/gpio_drive_strength.h new file mode 100644 index 0000000..bfcefb8 --- /dev/null +++ b/protocol/gpio_drive_strength.h @@ -0,0 +1,42 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _LIBHOTH_PROTOCOL_GPIO_DRIVE_STRENGTH_H_ +#define _LIBHOTH_PROTOCOL_GPIO_DRIVE_STRENGTH_H_ + +#include + +#include "protocol/host_cmd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HOTH_CMD_SET_GPIO_DRIVE_STRENGTH 0x3E56 +#define MAX_GPIO_DRIVE_STRENGTH 0xF +#define LIBHOTH_GPIO_DIO_PAD_OFFSET 128 + +struct hoth_request_set_gpio_drive_strength { + uint8_t pad; + uint8_t strength; +} __hoth_align1; + +int libhoth_set_gpio_drive_strength(struct libhoth_device* dev, uint8_t pad, + uint8_t strength); + +#ifdef __cplusplus +} +#endif + +#endif // _LIBHOTH_PROTOCOL_GPIO_DRIVE_STRENGTH_H_ diff --git a/protocol/gpio_drive_strength_test.cc b/protocol/gpio_drive_strength_test.cc new file mode 100644 index 0000000..4f15ca2 --- /dev/null +++ b/protocol/gpio_drive_strength_test.cc @@ -0,0 +1,35 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "protocol/gpio_drive_strength.h" + +#include +#include + +#include "protocol/test/libhoth_device_mock.h" + +using ::testing::_; +using ::testing::DoAll; +using ::testing::Return; + +TEST_F(LibHothTest, set_gpio_drive_strength_success) { + EXPECT_CALL(mock_, send(_, UsesCommand(HOTH_CMD_SET_GPIO_DRIVE_STRENGTH), _)) + .WillOnce(Return(LIBHOTH_OK)); + + uint32_t dummy; + EXPECT_CALL(mock_, receive) + .WillOnce(DoAll(CopyResp(&dummy, 0), Return(LIBHOTH_OK))); + + EXPECT_EQ(libhoth_set_gpio_drive_strength(&hoth_dev_, 10, 5), LIBHOTH_OK); +} diff --git a/protocol/meson.build b/protocol/meson.build index 86c0eaf..64b1b33 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -24,7 +24,8 @@ protocol_srcs = [ 'dfu_check.c', 'firmware_update.c', 'util.c', - 'console.c' + 'console.c', + 'gpio_drive_strength.c' ] incdir = libhoth_include_dirs