diff --git a/Documentation/devicetree/bindings/misc/gdsys,io-endpoint.txt b/Documentation/devicetree/bindings/misc/gdsys,io-endpoint.txt new file mode 100644 index 0000000..db2ff8c --- /dev/null +++ b/Documentation/devicetree/bindings/misc/gdsys,io-endpoint.txt @@ -0,0 +1,20 @@ +gdsys IO endpoint of IHS FPGA devices + +The IO endpoint of IHS FPGA devices is a packet-based transmission interface +that allows interconnected gdsys devices to send and receive data over the +FPGA's main ethernet connection. + +Required properties: +- compatible: must be "gdsys,io-endpoint" +- reg: describes the address and length of the endpoint's register map (within + the FPGA's register space) + +Example: + +fpga0_ep0 { + compatible = "gdsys,io-endpoint"; + reg = <0x020 0x10 + 0x320 0x10 + 0x340 0x10 + 0x360 0x10>; +}; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 4483134..118ff9f 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -286,6 +286,10 @@ mbox-names = "other", "test"; }; + misc-test { + compatible = "sandbox,misc_sandbox"; + }; + mmc2 { compatible = "sandbox,mmc"; }; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c031dfd..6bcd49a 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -277,4 +277,10 @@ config GDSYS_RXAUI_CTRL depends on MISC help Support gdsys FPGA's RXAUI control. + +config GDSYS_IOEP + bool "Enable gdsys IOEP driver" + depends on MISC + help + Support gdsys FPGA's IO endpoint driver. endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 4ce9d21..32ef4a5 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -39,7 +39,7 @@ ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SANDBOX) += spltest_sandbox.o endif endif -obj-$(CONFIG_SANDBOX) += syscon_sandbox.o +obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o obj-$(CONFIG_TEGRA_CAR) += tegra_car.o obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o @@ -53,4 +53,5 @@ obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_STM32_RCC) += stm32_rcc.o obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o +obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o diff --git a/drivers/misc/gdsys_ioep.c b/drivers/misc/gdsys_ioep.c new file mode 100644 index 0000000..7f17095 --- /dev/null +++ b/drivers/misc/gdsys_ioep.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * based on the cmd_ioloop driver/command, which is + * + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include "gdsys_ioep.h" + +/** + * struct gdsys_ioep_priv - Private data structure for IOEP devices + * @map: Register map to be used for the device + * @state: Flag to keep the current status of the RX control (enabled/disabled) + */ +struct gdsys_ioep_priv { + struct regmap *map; + bool state; +}; + +/** + * enum last_spec - Convenience enum for read data sanity check + * @READ_DATA_IS_LAST: The data to be read should be the final data of the + * current packet + * @READ_DATA_IS_NOT_LAST: The data to be read should not be the final data of + * the current packet + */ +enum last_spec { + READ_DATA_IS_LAST, + READ_DATA_IS_NOT_LAST, +}; + +static int gdsys_ioep_set_receive(struct udevice *dev, bool val) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + u16 state; + + priv->state = !priv->state; + + if (val) + state = CTRL_PROC_RECEIVE_ENABLE; + else + state = ~CTRL_PROC_RECEIVE_ENABLE; + + gdsys_ioep_set(priv->map, tx_control, state); + + if (val) { + /* Set device address to dummy 1 */ + gdsys_ioep_set(priv->map, device_address, 1); + } + + return !priv->state; +} + +static int gdsys_ioep_send(struct udevice *dev, int offset, + const void *buf, int size) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + int k; + u16 *p = (u16 *)buf; + + for (k = 0; k < size; ++k) + gdsys_ioep_set(priv->map, transmit_data, *(p++)); + + gdsys_ioep_set(priv->map, tx_control, CTRL_PROC_RECEIVE_ENABLE | + CTRL_FLUSH_TRANSMIT_BUFFER); + + return 0; +} + +/** + * receive_byte_buffer() - Read data from a IOEP device + * @dev: The IOEP device to read data from + * @len: The length of the data to read + * @buffer: The buffer to read the data into + * @last_spec: Flag to indicate if the data to be read in this call should be + * the final data of the current packet (i.e. it should be empty + * after this read) + * + * Return: 0 if OK, -ve on error + */ +static int receive_byte_buffer(struct udevice *dev, uint len, + u16 *buffer, enum last_spec last_spec) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + int k; + int ret = -EIO; + + for (k = 0; k < len; ++k) { + u16 rx_tx_status; + + gdsys_ioep_get(priv->map, receive_data, buffer++); + + gdsys_ioep_get(priv->map, rx_tx_status, &rx_tx_status); + /* + * Sanity check: If the data read should have been the last, + * but wasn't, something is wrong + */ + if (k == (len - 1) && (last_spec == READ_DATA_IS_NOT_LAST || + rx_tx_status & STATE_RX_DATA_LAST)) + ret = 0; + } + + if (ret) + debug("%s: Error while receiving bufer (err = %d)\n", + dev->name, ret); + + return ret; +} + +static int gdsys_ioep_receive(struct udevice *dev, int offset, void *buf, + int size) +{ + int ret; + struct io_generic_packet header; + u16 *p = (u16 *)buf; + const int header_words = sizeof(struct io_generic_packet) / sizeof(u16); + uint len; + + /* Read the packet header */ + ret = receive_byte_buffer(dev, header_words, p, READ_DATA_IS_NOT_LAST); + if (ret) { + debug("%s: Failed to read header data (err = %d)\n", + dev->name, ret); + return ret; + } + + memcpy(&header, p, header_words * sizeof(u16)); + p += header_words; + + /* Get payload data length */ + len = (header.packet_length + 1) / sizeof(u16); + + /* Read the packet payload */ + ret = receive_byte_buffer(dev, len, p, READ_DATA_IS_LAST); + if (ret) { + debug("%s: Failed to read payload data (err = %d)\n", + dev->name, ret); + return ret; + } + + return 0; +} + +static int gdsys_ioep_get_and_reset_status(struct udevice *dev, int msgid, + void *tx_msg, int tx_size, + void *rx_msg, int rx_size) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + const u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR | + STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR | + STATE_RX_PACKET_DROPPED | STATE_TX_ERR; + u16 *status = rx_msg; + + gdsys_ioep_get(priv->map, rx_tx_status, status); + + gdsys_ioep_set(priv->map, rx_tx_status, *status); + + return (*status & mask) ? 1 : 0; +} + +static const struct misc_ops gdsys_ioep_ops = { + .set_enabled = gdsys_ioep_set_receive, + .write = gdsys_ioep_send, + .read = gdsys_ioep_receive, + .call = gdsys_ioep_get_and_reset_status, +}; + +static int gdsys_ioep_probe(struct udevice *dev) +{ + struct gdsys_ioep_priv *priv = dev_get_priv(dev); + int ret; + + ret = regmap_init_mem(dev_ofnode(dev), &priv->map); + if (ret) { + debug("%s: Could not initialize regmap (err = %d)", + dev->name, ret); + return ret; + } + + priv->state = false; + + return 0; +} + +static const struct udevice_id gdsys_ioep_ids[] = { + { .compatible = "gdsys,io-endpoint" }, + { } +}; + +U_BOOT_DRIVER(gdsys_ioep) = { + .name = "gdsys_ioep", + .id = UCLASS_MISC, + .ops = &gdsys_ioep_ops, + .flags = DM_UC_FLAG_SEQ_ALIAS, + .of_match = gdsys_ioep_ids, + .probe = gdsys_ioep_probe, + .priv_auto_alloc_size = sizeof(struct gdsys_ioep_priv), +}; diff --git a/drivers/misc/gdsys_ioep.h b/drivers/misc/gdsys_ioep.h new file mode 100644 index 0000000..4d9524b --- /dev/null +++ b/drivers/misc/gdsys_ioep.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#ifndef __GDSYS_IOEP_H_ +#define __GDSYS_IOEP_H_ + +/** + * struct io_generic_packet - header structure for GDSYS IOEP packets + * @target_address: Target protocol address of the packet. + * @source_address: Source protocol address of the packet. + * @packet_type: Packet type. + * @bc: Block counter (filled in by FPGA). + * @packet_length: Length of the packet's payload bytes. + */ +struct io_generic_packet { + u16 target_address; + u16 source_address; + u8 packet_type; + u8 bc; + u16 packet_length; +} __attribute__((__packed__)); + +/** + * struct gdsys_ioep_regs - Registers of a IOEP device + * @transmit_data: Register that receives data to be sent + * @tx_control: TX control register + * @receive_data: Register filled with the received data + * @rx_tx_status: RX/TX status register + * @device_address: Register for setting/reading the device's address + * @target_address: Register for setting/reading the remote endpoint's address + * @int_enable: Interrupt/Interrupt enable register + */ +struct gdsys_ioep_regs { + u16 transmit_data; + u16 tx_control; + u16 receive_data; + u16 rx_tx_status; + u16 device_address; + u16 target_address; + u16 int_enable; +}; + +/** + * gdsys_ioep_set() - Convenience macro to write registers of a IOEP device + * @map: Register map to write the value in + * @member: Name of the member in the gdsys_ioep_regs structure to write + * @val: Value to write to the register + */ +#define gdsys_ioep_set(map, member, val) \ + regmap_set(map, struct gdsys_ioep_regs, member, val) + +/** + * gdsys_ioep_get() - Convenience macro to read registers of a IOEP device + * @map: Register map to read the value from + * @member: Name of the member in the gdsys_ioep_regs structure to read + * @valp: Pointer to buffer to read the register value into + */ +#define gdsys_ioep_get(map, member, valp) \ + regmap_get(map, struct gdsys_ioep_regs, member, valp) + +/** + * enum rx_tx_status_values - Enum to describe the fields of the rx_tx_status + * register + * @STATE_TX_PACKET_BUILDING: The device is currently building a packet + * (and accepting data for it) + * @STATE_TX_TRANSMITTING: A packet is currenly being transmitted + * @STATE_TX_BUFFER_FULL: The TX buffer is full + * @STATE_TX_ERR: A TX error occurred + * @STATE_RECEIVE_TIMEOUT: A receive timeout occurred + * @STATE_PROC_RX_STORE_TIMEOUT: A RX store timeout for a processor packet + * occurred + * @STATE_PROC_RX_RECEIVE_TIMEOUT: A RX receive timeout for a processor packet + * occurred + * @STATE_RX_DIST_ERR: A error occurred in the distribution block + * @STATE_RX_LENGTH_ERR: A length invalid error occurred + * @STATE_RX_FRAME_CTR_ERR: A frame count error occurred (two + * non-increasing frame count numbers + * encountered) + * @STATE_RX_FCS_ERR: A CRC error occurred + * @STATE_RX_PACKET_DROPPED: A RX packet has been dropped + * @STATE_RX_DATA_LAST: The data to be read is the final data of the + * current packet + * @STATE_RX_DATA_FIRST: The data to be read is the first data of the + * current packet + * @STATE_RX_DATA_AVAILABLE: RX data is available to be read + */ +enum rx_tx_status_values { + STATE_TX_PACKET_BUILDING = BIT(0), + STATE_TX_TRANSMITTING = BIT(1), + STATE_TX_BUFFER_FULL = BIT(2), + STATE_TX_ERR = BIT(3), + STATE_RECEIVE_TIMEOUT = BIT(4), + STATE_PROC_RX_STORE_TIMEOUT = BIT(5), + STATE_PROC_RX_RECEIVE_TIMEOUT = BIT(6), + STATE_RX_DIST_ERR = BIT(7), + STATE_RX_LENGTH_ERR = BIT(8), + STATE_RX_FRAME_CTR_ERR = BIT(9), + STATE_RX_FCS_ERR = BIT(10), + STATE_RX_PACKET_DROPPED = BIT(11), + STATE_RX_DATA_LAST = BIT(12), + STATE_RX_DATA_FIRST = BIT(13), + STATE_RX_DATA_AVAILABLE = BIT(15), +}; + +/** + * enum tx_control_values - Enum to describe the fields of the tx_control + * register + * @CTRL_PROC_RECEIVE_ENABLE: Enable packet reception for the processor + * @CTRL_FLUSH_TRANSMIT_BUFFER: Flush the transmit buffer (and send packet data) + */ +enum tx_control_values { + CTRL_PROC_RECEIVE_ENABLE = BIT(12), + CTRL_FLUSH_TRANSMIT_BUFFER = BIT(15), +}; + +/** + * enum int_enable_values - Enum to describe the fields of the int_enable + * register + * @IRQ_CPU_TRANSMITBUFFER_FREE_STATUS: The transmit buffer is free (packet + * data can be transmitted to the + * device) + * @IRQ_CPU_PACKET_TRANSMITTED_EVENT: A packet has been transmitted + * @IRQ_NEW_CPU_PACKET_RECEIVED_EVENT: A new packet has been received + * @IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS: RX packet data are available to be + * read + */ +enum int_enable_values { + IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = BIT(5), + IRQ_CPU_PACKET_TRANSMITTED_EVENT = BIT(6), + IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = BIT(7), + IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = BIT(8), +}; + +#endif /* __GDSYS_IOEP_H_ */ diff --git a/drivers/misc/misc-uclass.c b/drivers/misc/misc-uclass.c index 0dc62d0..f240cda 100644 --- a/drivers/misc/misc-uclass.c +++ b/drivers/misc/misc-uclass.c @@ -55,6 +55,16 @@ int misc_call(struct udevice *dev, int msgid, void *tx_msg, int tx_size, return ops->call(dev, msgid, tx_msg, tx_size, rx_msg, rx_size); } +int misc_set_enabled(struct udevice *dev, bool val) +{ + const struct misc_ops *ops = device_get_ops(dev); + + if (!ops->set_enabled) + return -ENOSYS; + + return ops->set_enabled(dev, val); +} + UCLASS_DRIVER(misc) = { .id = UCLASS_MISC, .name = "misc", diff --git a/drivers/misc/misc_sandbox.c b/drivers/misc/misc_sandbox.c new file mode 100644 index 0000000..e4164f7 --- /dev/null +++ b/drivers/misc/misc_sandbox.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#include +#include +#include + +struct misc_sandbox_priv { + u8 mem[128]; + ulong last_ioctl; + bool enabled; +}; + +int misc_sandbox_read(struct udevice *dev, int offset, void *buf, int size) +{ + struct misc_sandbox_priv *priv = dev_get_priv(dev); + + memcpy(buf, priv->mem + offset, size); + + return 0; +} + +int misc_sandbox_write(struct udevice *dev, int offset, const void *buf, + int size) +{ + struct misc_sandbox_priv *priv = dev_get_priv(dev); + + memcpy(priv->mem + offset, buf, size); + + return 0; +} + +int misc_sandbox_ioctl(struct udevice *dev, unsigned long request, void *buf) +{ + struct misc_sandbox_priv *priv = dev_get_priv(dev); + + priv->last_ioctl = request; + + return 0; +} + +int misc_sandbox_call(struct udevice *dev, int msgid, void *tx_msg, + int tx_size, void *rx_msg, int rx_size) +{ + struct misc_sandbox_priv *priv = dev_get_priv(dev); + + if (msgid == 0) { + int num = *(int *)tx_msg; + + switch (num) { + case 0: + strncpy(rx_msg, "Zero", rx_size); + break; + case 1: + strncpy(rx_msg, "One", rx_size); + break; + case 2: + strncpy(rx_msg, "Two", rx_size); + break; + default: + return -EINVAL; + } + } + + if (msgid == 1) { + int num = *(int *)tx_msg; + + switch (num) { + case 0: + strncpy(rx_msg, "Forty", rx_size); + break; + case 1: + strncpy(rx_msg, "Forty-one", rx_size); + break; + case 2: + strncpy(rx_msg, "Forty-two", rx_size); + break; + default: + return -EINVAL; + } + } + + if (msgid == 2) + memcpy(rx_msg, &priv->last_ioctl, sizeof(priv->last_ioctl)); + + if (msgid == 3) + memcpy(rx_msg, &priv->enabled, sizeof(priv->enabled)); + + return 0; +} + +int misc_sandbox_set_enabled(struct udevice *dev, bool val) +{ + struct misc_sandbox_priv *priv = dev_get_priv(dev); + + priv->enabled = !priv->enabled; + + return 0; +} + +static const struct misc_ops misc_sandbox_ops = { + .read = misc_sandbox_read, + .write = misc_sandbox_write, + .ioctl = misc_sandbox_ioctl, + .call = misc_sandbox_call, + .set_enabled = misc_sandbox_set_enabled, +}; + +int misc_sandbox_probe(struct udevice *dev) +{ + struct misc_sandbox_priv *priv = dev_get_priv(dev); + + priv->enabled = true; + + return 0; +} + +static const struct udevice_id misc_sandbox_ids[] = { + { .compatible = "sandbox,misc_sandbox" }, + { } +}; + +U_BOOT_DRIVER(misc_sandbox) = { + .name = "misc_sandbox", + .id = UCLASS_MISC, + .ops = &misc_sandbox_ops, + .of_match = misc_sandbox_ids, + .probe = misc_sandbox_probe, + .priv_auto_alloc_size = sizeof(struct misc_sandbox_priv), +}; diff --git a/include/misc.h b/include/misc.h index 68f8e64..5051585 100644 --- a/include/misc.h +++ b/include/misc.h @@ -6,38 +6,47 @@ #ifndef _MISC_H_ #define _MISC_H_ -/* - * Read the device to buffer, optional. - * +/** + * misc_read() - Read the device to buffer, optional. * @dev: the device * @offset: offset to read the device * @buf: pointer to data buffer * @size: data size in bytes to read the device - * @return: 0 if OK, -ve on error + * + * Return: 0 if OK, -ve on error */ int misc_read(struct udevice *dev, int offset, void *buf, int size); -/* - * Write buffer to the device, optional. - * + +/** + * misc_write() - Write buffer to the device, optional. * @dev: the device * @offset: offset to write the device * @buf: pointer to data buffer * @size: data size in bytes to write the device - * @return: 0 if OK, -ve on error + * + * Return: 0 if OK, -ve on error */ int misc_write(struct udevice *dev, int offset, void *buf, int size); -/* - * Assert command to the device, optional. - * + +/** + * misc_ioctl() - Assert command to the device, optional. * @dev: the device * @request: command to be sent to the device * @buf: pointer to buffer related to the request - * @return: 0 if OK, -ve on error + * + * Return: 0 if OK, -ve on error */ int misc_ioctl(struct udevice *dev, unsigned long request, void *buf); -/* - * Send a message to the device and wait for a response. +/** + * misc_call() - Send a message to the device and wait for a response. + * @dev: the device. + * @msgid: the message ID/number to send. + * @tx_msg: the request/transmit message payload. + * @tx_size: the size of the buffer pointed at by tx_msg. + * @rx_msg: the buffer to receive the response message payload. May be NULL if + * the caller only cares about the error code. + * @rx_size: the size of the buffer pointed at by rx_msg. * * The caller provides the message type/ID and payload to be sent. * The callee constructs any message header required, transmits it to the @@ -45,18 +54,28 @@ int misc_ioctl(struct udevice *dev, unsigned long request, void *buf); * strips any message header from the response, and returns the error code * (or a parsed version of it) and the response message payload. * - * @dev: the device. - * @msgid: the message ID/number to send. - * tx_msg: the request/transmit message payload. - * tx_size: the size of the buffer pointed at by tx_msg. - * rx_msg: the buffer to receive the response message payload. May be NULL if - * the caller only cares about the error code. - * rx_size: the size of the buffer pointed at by rx_msg. - * @return the response message size if OK, -ve on error + * Return: the response message size if OK, -ve on error */ int misc_call(struct udevice *dev, int msgid, void *tx_msg, int tx_size, void *rx_msg, int rx_size); +/** + * misc_set_enabled() - Enable or disable a device. + * @dev: the device to enable or disable. + * @val: the flag that tells the driver to either enable or disable the device. + * + * The semantics of "disable" and "enable" should be understood here as + * activating or deactivating the device's primary function, hence a "disabled" + * device should be dormant, but still answer to commands and queries. + * + * A probed device may start in a disabled or enabled state, depending on the + * driver and hardware. + * + * Return: -ve on error, 0 if the previous state was "disabled", 1 if the + * previous state was "enabled" + */ +int misc_set_enabled(struct udevice *dev, bool val); + /* * struct misc_ops - Driver model Misc operations * @@ -64,50 +83,62 @@ int misc_call(struct udevice *dev, int msgid, void *tx_msg, int tx_size, * use driver model. */ struct misc_ops { - /* + /** * Read the device to buffer, optional. - * * @dev: the device * @offset: offset to read the device * @buf: pointer to data buffer * @size: data size in bytes to read the device - * @return: 0 if OK, -ve on error + * + * Return: 0 if OK, -ve on error */ int (*read)(struct udevice *dev, int offset, void *buf, int size); - /* + + /** * Write buffer to the device, optional. - * * @dev: the device * @offset: offset to write the device * @buf: pointer to data buffer * @size: data size in bytes to write the device - * @return: 0 if OK, -ve on error + * + * Return: 0 if OK, -ve on error */ int (*write)(struct udevice *dev, int offset, const void *buf, int size); - /* + /** * Assert command to the device, optional. - * * @dev: the device * @request: command to be sent to the device * @buf: pointer to buffer related to the request - * @return: 0 if OK, -ve on error + * + * Return: 0 if OK, -ve on error */ int (*ioctl)(struct udevice *dev, unsigned long request, void *buf); - /* + + /** * Send a message to the device and wait for a response. - * * @dev: the device * @msgid: the message ID/number to send - * tx_msg: the request/transmit message payload - * tx_size: the size of the buffer pointed at by tx_msg - * rx_msg: the buffer to receive the response message payload. May be - * NULL if the caller only cares about the error code. - * rx_size: the size of the buffer pointed at by rx_msg - * @return the response message size if OK, -ve on error + * @tx_msg: the request/transmit message payload + * @tx_size: the size of the buffer pointed at by tx_msg + * @rx_msg: the buffer to receive the response message payload. May be + * NULL if the caller only cares about the error code. + * @rx_size: the size of the buffer pointed at by rx_msg + * + * Return: the response message size if OK, -ve on error */ int (*call)(struct udevice *dev, int msgid, void *tx_msg, int tx_size, void *rx_msg, int rx_size); + /** + * Enable or disable a device, optional. + * @dev: the device to enable. + * @val: the flag that tells the driver to either enable or disable the + * device. + * + * Return: -ve on error, 0 if the previous state was "disabled", 1 if + * the previous state was "enabled" + */ + int (*set_enabled)(struct udevice *dev, bool val); }; #endif /* _MISC_H_ */ diff --git a/test/dm/Makefile b/test/dm/Makefile index 564e846..67c1fe6 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -45,4 +45,5 @@ obj-$(CONFIG_ADC) += adc.o obj-$(CONFIG_SPMI) += spmi.o obj-$(CONFIG_WDT) += wdt.o obj-$(CONFIG_AXI) += axi.o +obj-$(CONFIG_MISC) += misc.o endif diff --git a/test/dm/misc.c b/test/dm/misc.c new file mode 100644 index 0000000..6127966 --- /dev/null +++ b/test/dm/misc.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#include +#include +#include +#include +#include + +static int dm_test_misc(struct unit_test_state *uts) +{ + struct udevice *dev; + u8 buf[16]; + int id; + ulong last_ioctl; + bool enabled; + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "misc-test", &dev)); + + /* Read / write tests */ + ut_assertok(misc_write(dev, 0, "TEST", 4)); + ut_assertok(misc_write(dev, 4, "WRITE", 5)); + ut_assertok(misc_read(dev, 0, buf, 9)); + + ut_assertok(memcmp(buf, "TESTWRITE", 9)); + + /* Call tests */ + + id = 0; + ut_assertok(misc_call(dev, 0, &id, 4, buf, 16)); + ut_assertok(memcmp(buf, "Zero", 4)); + + id = 2; + ut_assertok(misc_call(dev, 0, &id, 4, buf, 16)); + ut_assertok(memcmp(buf, "Two", 3)); + + ut_assertok(misc_call(dev, 1, &id, 4, buf, 16)); + ut_assertok(memcmp(buf, "Forty-two", 9)); + + id = 1; + ut_assertok(misc_call(dev, 1, &id, 4, buf, 16)); + ut_assertok(memcmp(buf, "Forty-one", 9)); + + /* IOCTL tests */ + + ut_assertok(misc_ioctl(dev, 6, NULL)); + /* Read back last issued ioctl */ + ut_assertok(misc_call(dev, 2, NULL, 0, &last_ioctl, + sizeof(last_ioctl))); + ut_asserteq(6, last_ioctl) + + ut_assertok(misc_ioctl(dev, 23, NULL)); + /* Read back last issued ioctl */ + ut_assertok(misc_call(dev, 2, NULL, 0, &last_ioctl, + sizeof(last_ioctl))); + ut_asserteq(23, last_ioctl) + + /* Enable / disable tests */ + + /* Read back enable/disable status */ + ut_assertok(misc_call(dev, 3, NULL, 0, &enabled, + sizeof(enabled))); + ut_asserteq(true, enabled); + + ut_assertok(misc_set_enabled(dev, false)); + /* Read back enable/disable status */ + ut_assertok(misc_call(dev, 3, NULL, 0, &enabled, + sizeof(enabled))); + ut_asserteq(false, enabled); + + ut_assertok(misc_set_enabled(dev, true)); + /* Read back enable/disable status */ + ut_assertok(misc_call(dev, 3, NULL, 0, &enabled, + sizeof(enabled))); + ut_asserteq(true, enabled); + + return 0; +} + +DM_TEST(dm_test_misc, DM_TESTF_SCAN_FDT);