diff --git a/CODEOWNERS b/CODEOWNERS index ec50aac245..61561fa25e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -169,6 +169,7 @@ /drivers/dma/*sam0* @Sizurka /drivers/dma/dma_stm32* @cybertale /drivers/dma/*pl330* @raveenp +/drivers/ec_host_cmd_periph/ @jettr /drivers/eeprom/ @henrikbrixandersen /drivers/eeprom/eeprom_stm32.c @KwonTae-young /drivers/entropy/*rv32m1* @MaureenHelm diff --git a/boards/posix/native_posix/native_posix.dts b/boards/posix/native_posix/native_posix.dts index 708cc6698b..639bacfe50 100644 --- a/boards/posix/native_posix/native_posix.dts +++ b/boards/posix/native_posix/native_posix.dts @@ -19,6 +19,7 @@ zephyr,flash = &flash0; zephyr,entropy = &rng; zephyr,flash-controller = &flashcontroller0; + zephyr,ec-host-interface = &hcp; }; aliases { @@ -112,4 +113,10 @@ label = "COUNTER_0"; }; + hcp: ec-host-cmd-periph { + status = "okay"; + compatible = "zephyr,sim-ec-host-cmd-periph"; + label = "EC_HOST_CMD_SIM"; + }; + }; diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index d409fabd45..db17b7db98 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -14,6 +14,7 @@ add_subdirectory_ifdef(CONFIG_DAC dac) add_subdirectory_ifdef(CONFIG_DISPLAY display) add_subdirectory_ifdef(CONFIG_DMA dma) add_subdirectory_ifdef(CONFIG_GPIO gpio) +add_subdirectory_ifdef(CONFIG_EC_HOST_CMD_PERIPH ec_host_cmd_periph) add_subdirectory_ifdef(CONFIG_I2C i2c) add_subdirectory_ifdef(CONFIG_I2S i2s) add_subdirectory_ifdef(CONFIG_IEEE802154 ieee802154) diff --git a/drivers/Kconfig b/drivers/Kconfig index 2952fe458e..eafe17c5ca 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -15,6 +15,8 @@ source "drivers/console/Kconfig" source "drivers/debug/Kconfig" +source "drivers/ec_host_cmd_periph/Kconfig" + source "drivers/ethernet/Kconfig" source "drivers/net/Kconfig" diff --git a/drivers/ec_host_cmd_periph/CMakeLists.txt b/drivers/ec_host_cmd_periph/CMakeLists.txt new file mode 100644 index 0000000000..2df8e17d64 --- /dev/null +++ b/drivers/ec_host_cmd_periph/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef( + CONFIG_EC_HOST_CMD_SIMULATOR + ec_host_cmd_simulator.c) +zephyr_library_sources_ifdef(CONFIG_USERSPACE ec_host_cmd_periph_handlers.c) diff --git a/drivers/ec_host_cmd_periph/Kconfig b/drivers/ec_host_cmd_periph/Kconfig new file mode 100644 index 0000000000..fa24011573 --- /dev/null +++ b/drivers/ec_host_cmd_periph/Kconfig @@ -0,0 +1,20 @@ +# Host Command Peripheral simulator config + +# Copyright (c) 2020 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +menuconfig EC_HOST_CMD_PERIPH + bool "Embedded Controller Host Command peripheral support" + help + Enable the embedded controller host command peripheral driver. This + is needed by the EC host command framework to send and receive data + on the appropriate EC host bus. + +if EC_HOST_CMD_PERIPH + +config EC_HOST_CMD_SIMULATOR + bool "Embedded Controller Host Command Peripheral Simulator" + help + Enable the EC host command simulator. + +endif # EC_HOST_CMD_PERIPH diff --git a/drivers/ec_host_cmd_periph/ec_host_cmd_periph_handlers.c b/drivers/ec_host_cmd_periph/ec_host_cmd_periph_handlers.c new file mode 100644 index 0000000000..00f0672f4e --- /dev/null +++ b/drivers/ec_host_cmd_periph/ec_host_cmd_periph_handlers.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static inline void +z_vrfy_ec_host_cmd_periph_init(const struct device *dev, + struct ec_host_cmd_periph_rx_ctx *rx_ctx) +{ + struct ec_host_cmd_periph_rx_ctx local_rx_ctx; + + Z_OOPS(Z_SYSCALL_OBJ_INIT(dev, K_OBJ_DRIVER_EC_HOST_CMD_PERIPH_API)); + + z_impl_host_cmd_periph_init(dev, &local_rx_ctx); + + Z_OOPS(z_user_to_copy(&local_rx_ctx, rx_ctx, sizeof(*rx_ctx))); +} +#include + +static inline void +z_vrfy_ec_host_cmd_periph_send(const struct device *dev, + const struct ec_host_cmd_periph_tx_buf *tx_buf) +{ + struct ec_host_cmd_periph_tx_buf local_tx_buf; + + Z_OOPS(Z_SYSCALL_OBJ(dev, K_OBJ_DRIVER_EC_HOST_CMD_PERIPH_API)); + Z_OOPS(z_user_from_copy(&local_tx_buf, tx_buf, sizeof(*tx_buf))); + + /* Ensure that user thread has acces to read buffer since + * device will read from this memory location. + */ + Z_OOPS(Z_SYSCALL_MEMORY_READ(local_tx_buf.buf, local_tx_buf.size)); + + z_impl_host_cmd_periph_send(dev, &local_tx_buf); +} +#include diff --git a/drivers/ec_host_cmd_periph/ec_host_cmd_simulator.c b/drivers/ec_host_cmd_periph/ec_host_cmd_simulator.c new file mode 100644 index 0000000000..b6661e3e3a --- /dev/null +++ b/drivers/ec_host_cmd_periph/ec_host_cmd_simulator.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_sim_ec_host_cmd_periph + +#include +#include +#include + +#ifndef CONFIG_ARCH_POSIX +#error Simulator only valid on posix +#endif + +static uint8_t rx_buffer[256]; +static size_t rx_buffer_len; + +/* Allow writing to rx buff at startup and block on reading. */ +static K_SEM_DEFINE(handler_owns, 0, 1); +static K_SEM_DEFINE(dev_owns, 1, 1); + +static ec_host_cmd_periph_api_send tx; + +int ec_host_cmd_periph_sim_init(const struct device *dev, + struct ec_host_cmd_periph_rx_ctx *rx_ctx) +{ + if (rx_ctx == NULL) { + return -EINVAL; + } + + rx_ctx->buf = rx_buffer; + rx_ctx->len = &rx_buffer_len; + rx_ctx->dev_owns = &dev_owns; + rx_ctx->handler_owns = &handler_owns; + + return 0; +} + +int ec_host_cmd_periph_sim_send(const struct device *dev, + const struct ec_host_cmd_periph_tx_buf *buf) +{ + if (tx != NULL) { + return tx(dev, buf); + } + + return 0; +} + +void ec_host_cmd_periph_sim_install_send_cb(ec_host_cmd_periph_api_send cb) +{ + tx = cb; +} + +int ec_host_cmd_periph_sim_data_received(const uint8_t *buffer, size_t len) +{ + if (sizeof(rx_buffer) < len) { + return -ENOMEM; + } + if (k_sem_take(&dev_owns, K_NO_WAIT) != 0) { + return -EBUSY; + } + + memcpy(rx_buffer, buffer, len); + rx_buffer_len = len; + + k_sem_give(&handler_owns); + return 0; +} + +static const struct ec_host_cmd_periph_api ec_host_cmd_api = { + .init = &ec_host_cmd_periph_sim_init, + .send = &ec_host_cmd_periph_sim_send, +}; + +static int ec_host_cmd_sim_init(const struct device *dev) +{ + return 0; +} + +/* Assume only one simulator */ +DEVICE_AND_API_INIT(ec_host_cmd_simulator, DT_INST_LABEL(0), + ec_host_cmd_sim_init, NULL, NULL, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &ec_host_cmd_api); diff --git a/dts/bindings/ec_host_cmd_perhip/zephyr,sim-ec-host-cmd-periph.yaml b/dts/bindings/ec_host_cmd_perhip/zephyr,sim-ec-host-cmd-periph.yaml new file mode 100644 index 0000000000..a6b12b8d40 --- /dev/null +++ b/dts/bindings/ec_host_cmd_perhip/zephyr,sim-ec-host-cmd-periph.yaml @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +description: Simulated Host Command Peripheral + +compatible: "zephyr,sim-ec-host-cmd-periph" + +include: base.yaml + +properties: + label: + required: true diff --git a/include/drivers/ec_host_cmd_periph.h b/include/drivers/ec_host_cmd_periph.h new file mode 100644 index 0000000000..7acc5a7e32 --- /dev/null +++ b/include/drivers/ec_host_cmd_periph.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2020 Google LLC. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public APIs for Host Command Peripherals that respond to host commands + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_HOST_CMD_PERIPH_H_ +#define ZEPHYR_INCLUDE_DRIVERS_HOST_CMD_PERIPH_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Host Command Peripherals API + * @defgroup ec_host_cmd_periph Host Command Peripherals API + * @ingroup io_interfaces + * @{ + */ + +/** + * @brief Context for host command peripheral and framework to pass rx data + */ +struct ec_host_cmd_periph_rx_ctx { + /** Buffer written to by device (when dev_owns) and read from by + * command framework and handler (when handler_owns). Buffer is owned + * by devices and lives as long as device is valid. Device will never + * read from this buffer (for security reasons). + */ + uint8_t *buf; + /** Number of bytes written to @a buf by device (when dev_owns). */ + size_t *len; + /** Device will take when it needs to write to @a buf and @a size. */ + struct k_sem *dev_owns; + /** Handler will take so it can read @a buf and @a size */ + struct k_sem *handler_owns; +}; + +/** + * @brief Context for host command peripheral and framework to pass tx data + */ +struct ec_host_cmd_periph_tx_buf { + /** Data to write to the host */ + void *buf; + /** Number of bytes to write from @a buf */ + size_t len; +}; + +typedef int (*ec_host_cmd_periph_api_init)( + const struct device *dev, struct ec_host_cmd_periph_rx_ctx *rx_ctx); + +typedef int (*ec_host_cmd_periph_api_send)( + const struct device *dev, + const struct ec_host_cmd_periph_tx_buf *tx_buf); + +__subsystem struct ec_host_cmd_periph_api { + ec_host_cmd_periph_api_init init; + ec_host_cmd_periph_api_send send; +}; + +/** + * @brief Initialize a host command device + * + * This routine initializes a host command device, prior to its first use. The + * receive context object are an output of this function and are valid + * for the lifetime of this device. The RX context is used by the client to + * receive data from the host. + * + * @param dev Pointer to the device structure for the driver instance. + * @param rx_ctx [out] The receiving context object that are valid for the + * lifetime of the device. These objects are used to receive data + * from the driver when the host send data. + * + * @retval 0 if successful + */ +__syscall int ec_host_cmd_periph_init(const struct device *dev, + struct ec_host_cmd_periph_rx_ctx *rx_ctx); + +static inline int +z_impl_ec_host_cmd_periph_init(const struct device *dev, + struct ec_host_cmd_periph_rx_ctx *rx_ctx) +{ + const struct ec_host_cmd_periph_api *api = + (const struct ec_host_cmd_periph_api *)dev->api; + + return api->init(dev, rx_ctx); +} + +/** + * @brief Sends the specified data to the host + * + * Sends the data specified in @a tx_buf to the host over the host communication + * bus. + * + * @param dev Pointer to the device structure for the driver instance. + * @param tx_buf The data to transmit to the host. + * + * @retval 0 if successful + */ +__syscall int ec_host_cmd_periph_send( + const struct device *dev, + const struct ec_host_cmd_periph_tx_buf *tx_buf); + +static inline int z_impl_ec_host_cmd_periph_send( + const struct device *dev, + const struct ec_host_cmd_periph_tx_buf *tx_buf) +{ + const struct ec_host_cmd_periph_api *api = + (const struct ec_host_cmd_periph_api *)dev->api; + + return api->send(dev, tx_buf); +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* ZEPHYR_INCLUDE_DRIVERS_HOST_CMD_PERIPH_H_ */ diff --git a/include/drivers/ec_host_cmd_periph/ec_host_cmd_simulator.h b/include/drivers/ec_host_cmd_periph/ec_host_cmd_simulator.h new file mode 100644 index 0000000000..14ba31fe8c --- /dev/null +++ b/include/drivers/ec_host_cmd_periph/ec_host_cmd_simulator.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Header for commands to interact with the simulator outside of normal + * device interface. + */ + +/* For ec_host_cmd_periph_api_send function pointer type */ +#include + +/** + * @brief Install callback for when this device would sends data to host + * + * When this host command simulator device should send data to the host, it + * will call the the callback parameter provided by this function. Note that + * only one callback may be installed at a time. Calling this a second time + * will override the first callback installation. + * + * @param cb Callback that is called when device would send data to host. + * + * @return N/A + */ +void ec_host_cmd_periph_sim_install_send_cb(ec_host_cmd_periph_api_send cb); + +/** + * @brief Simulate receiving data from host as passed in to this function + * + * Calling this function simulates that data was sent from the host to the DUT. + * + * @param buffer The buffer that contains the data to receive. + * @param len The number of bytes that are received from the above buffer. + * + * @retval 0 if successful + * @retval -ENOMEM if len is greater than the RX buffer size. + * @retval -EBUSY if the host command framework is busy with another request. + */ +int ec_host_cmd_periph_sim_data_received(const uint8_t *buffer, size_t len);