Commit 8fee226da36f799e69041b2ab381064693199c7f
Exists in
smarc_8mq_lf_v2020.04
and in
11 other branches
Merge branch 'agust@denx.de' of git://git.denx.de/u-boot-staging
Showing 11 changed files Side-by-side Diff
Documentation/devicetree/bindings/misc/gdsys,io-endpoint.txt
1 | +gdsys IO endpoint of IHS FPGA devices | |
2 | + | |
3 | +The IO endpoint of IHS FPGA devices is a packet-based transmission interface | |
4 | +that allows interconnected gdsys devices to send and receive data over the | |
5 | +FPGA's main ethernet connection. | |
6 | + | |
7 | +Required properties: | |
8 | +- compatible: must be "gdsys,io-endpoint" | |
9 | +- reg: describes the address and length of the endpoint's register map (within | |
10 | + the FPGA's register space) | |
11 | + | |
12 | +Example: | |
13 | + | |
14 | +fpga0_ep0 { | |
15 | + compatible = "gdsys,io-endpoint"; | |
16 | + reg = <0x020 0x10 | |
17 | + 0x320 0x10 | |
18 | + 0x340 0x10 | |
19 | + 0x360 0x10>; | |
20 | +}; |
arch/sandbox/dts/test.dts
drivers/misc/Kconfig
drivers/misc/Makefile
... | ... | @@ -39,7 +39,7 @@ |
39 | 39 | obj-$(CONFIG_SANDBOX) += spltest_sandbox.o |
40 | 40 | endif |
41 | 41 | endif |
42 | -obj-$(CONFIG_SANDBOX) += syscon_sandbox.o | |
42 | +obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o | |
43 | 43 | obj-$(CONFIG_TEGRA_CAR) += tegra_car.o |
44 | 44 | obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o |
45 | 45 | obj-$(CONFIG_TWL4030_LED) += twl4030_led.o |
... | ... | @@ -53,5 +53,6 @@ |
53 | 53 | obj-$(CONFIG_STM32_RCC) += stm32_rcc.o |
54 | 54 | obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o |
55 | 55 | obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o |
56 | +obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o | |
56 | 57 | obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o |
drivers/misc/gdsys_ioep.c
1 | +// SPDX-License-Identifier: GPL-2.0+ | |
2 | +/* | |
3 | + * (C) Copyright 2017 | |
4 | + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc | |
5 | + * | |
6 | + * based on the cmd_ioloop driver/command, which is | |
7 | + * | |
8 | + * (C) Copyright 2014 | |
9 | + * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc | |
10 | + * | |
11 | + * SPDX-License-Identifier: GPL-2.0+ | |
12 | + */ | |
13 | + | |
14 | +#include <common.h> | |
15 | +#include <dm.h> | |
16 | +#include <misc.h> | |
17 | +#include <regmap.h> | |
18 | + | |
19 | +#include "gdsys_ioep.h" | |
20 | + | |
21 | +/** | |
22 | + * struct gdsys_ioep_priv - Private data structure for IOEP devices | |
23 | + * @map: Register map to be used for the device | |
24 | + * @state: Flag to keep the current status of the RX control (enabled/disabled) | |
25 | + */ | |
26 | +struct gdsys_ioep_priv { | |
27 | + struct regmap *map; | |
28 | + bool state; | |
29 | +}; | |
30 | + | |
31 | +/** | |
32 | + * enum last_spec - Convenience enum for read data sanity check | |
33 | + * @READ_DATA_IS_LAST: The data to be read should be the final data of the | |
34 | + * current packet | |
35 | + * @READ_DATA_IS_NOT_LAST: The data to be read should not be the final data of | |
36 | + * the current packet | |
37 | + */ | |
38 | +enum last_spec { | |
39 | + READ_DATA_IS_LAST, | |
40 | + READ_DATA_IS_NOT_LAST, | |
41 | +}; | |
42 | + | |
43 | +static int gdsys_ioep_set_receive(struct udevice *dev, bool val) | |
44 | +{ | |
45 | + struct gdsys_ioep_priv *priv = dev_get_priv(dev); | |
46 | + u16 state; | |
47 | + | |
48 | + priv->state = !priv->state; | |
49 | + | |
50 | + if (val) | |
51 | + state = CTRL_PROC_RECEIVE_ENABLE; | |
52 | + else | |
53 | + state = ~CTRL_PROC_RECEIVE_ENABLE; | |
54 | + | |
55 | + gdsys_ioep_set(priv->map, tx_control, state); | |
56 | + | |
57 | + if (val) { | |
58 | + /* Set device address to dummy 1 */ | |
59 | + gdsys_ioep_set(priv->map, device_address, 1); | |
60 | + } | |
61 | + | |
62 | + return !priv->state; | |
63 | +} | |
64 | + | |
65 | +static int gdsys_ioep_send(struct udevice *dev, int offset, | |
66 | + const void *buf, int size) | |
67 | +{ | |
68 | + struct gdsys_ioep_priv *priv = dev_get_priv(dev); | |
69 | + int k; | |
70 | + u16 *p = (u16 *)buf; | |
71 | + | |
72 | + for (k = 0; k < size; ++k) | |
73 | + gdsys_ioep_set(priv->map, transmit_data, *(p++)); | |
74 | + | |
75 | + gdsys_ioep_set(priv->map, tx_control, CTRL_PROC_RECEIVE_ENABLE | | |
76 | + CTRL_FLUSH_TRANSMIT_BUFFER); | |
77 | + | |
78 | + return 0; | |
79 | +} | |
80 | + | |
81 | +/** | |
82 | + * receive_byte_buffer() - Read data from a IOEP device | |
83 | + * @dev: The IOEP device to read data from | |
84 | + * @len: The length of the data to read | |
85 | + * @buffer: The buffer to read the data into | |
86 | + * @last_spec: Flag to indicate if the data to be read in this call should be | |
87 | + * the final data of the current packet (i.e. it should be empty | |
88 | + * after this read) | |
89 | + * | |
90 | + * Return: 0 if OK, -ve on error | |
91 | + */ | |
92 | +static int receive_byte_buffer(struct udevice *dev, uint len, | |
93 | + u16 *buffer, enum last_spec last_spec) | |
94 | +{ | |
95 | + struct gdsys_ioep_priv *priv = dev_get_priv(dev); | |
96 | + int k; | |
97 | + int ret = -EIO; | |
98 | + | |
99 | + for (k = 0; k < len; ++k) { | |
100 | + u16 rx_tx_status; | |
101 | + | |
102 | + gdsys_ioep_get(priv->map, receive_data, buffer++); | |
103 | + | |
104 | + gdsys_ioep_get(priv->map, rx_tx_status, &rx_tx_status); | |
105 | + /* | |
106 | + * Sanity check: If the data read should have been the last, | |
107 | + * but wasn't, something is wrong | |
108 | + */ | |
109 | + if (k == (len - 1) && (last_spec == READ_DATA_IS_NOT_LAST || | |
110 | + rx_tx_status & STATE_RX_DATA_LAST)) | |
111 | + ret = 0; | |
112 | + } | |
113 | + | |
114 | + if (ret) | |
115 | + debug("%s: Error while receiving bufer (err = %d)\n", | |
116 | + dev->name, ret); | |
117 | + | |
118 | + return ret; | |
119 | +} | |
120 | + | |
121 | +static int gdsys_ioep_receive(struct udevice *dev, int offset, void *buf, | |
122 | + int size) | |
123 | +{ | |
124 | + int ret; | |
125 | + struct io_generic_packet header; | |
126 | + u16 *p = (u16 *)buf; | |
127 | + const int header_words = sizeof(struct io_generic_packet) / sizeof(u16); | |
128 | + uint len; | |
129 | + | |
130 | + /* Read the packet header */ | |
131 | + ret = receive_byte_buffer(dev, header_words, p, READ_DATA_IS_NOT_LAST); | |
132 | + if (ret) { | |
133 | + debug("%s: Failed to read header data (err = %d)\n", | |
134 | + dev->name, ret); | |
135 | + return ret; | |
136 | + } | |
137 | + | |
138 | + memcpy(&header, p, header_words * sizeof(u16)); | |
139 | + p += header_words; | |
140 | + | |
141 | + /* Get payload data length */ | |
142 | + len = (header.packet_length + 1) / sizeof(u16); | |
143 | + | |
144 | + /* Read the packet payload */ | |
145 | + ret = receive_byte_buffer(dev, len, p, READ_DATA_IS_LAST); | |
146 | + if (ret) { | |
147 | + debug("%s: Failed to read payload data (err = %d)\n", | |
148 | + dev->name, ret); | |
149 | + return ret; | |
150 | + } | |
151 | + | |
152 | + return 0; | |
153 | +} | |
154 | + | |
155 | +static int gdsys_ioep_get_and_reset_status(struct udevice *dev, int msgid, | |
156 | + void *tx_msg, int tx_size, | |
157 | + void *rx_msg, int rx_size) | |
158 | +{ | |
159 | + struct gdsys_ioep_priv *priv = dev_get_priv(dev); | |
160 | + const u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR | | |
161 | + STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR | | |
162 | + STATE_RX_PACKET_DROPPED | STATE_TX_ERR; | |
163 | + u16 *status = rx_msg; | |
164 | + | |
165 | + gdsys_ioep_get(priv->map, rx_tx_status, status); | |
166 | + | |
167 | + gdsys_ioep_set(priv->map, rx_tx_status, *status); | |
168 | + | |
169 | + return (*status & mask) ? 1 : 0; | |
170 | +} | |
171 | + | |
172 | +static const struct misc_ops gdsys_ioep_ops = { | |
173 | + .set_enabled = gdsys_ioep_set_receive, | |
174 | + .write = gdsys_ioep_send, | |
175 | + .read = gdsys_ioep_receive, | |
176 | + .call = gdsys_ioep_get_and_reset_status, | |
177 | +}; | |
178 | + | |
179 | +static int gdsys_ioep_probe(struct udevice *dev) | |
180 | +{ | |
181 | + struct gdsys_ioep_priv *priv = dev_get_priv(dev); | |
182 | + int ret; | |
183 | + | |
184 | + ret = regmap_init_mem(dev_ofnode(dev), &priv->map); | |
185 | + if (ret) { | |
186 | + debug("%s: Could not initialize regmap (err = %d)", | |
187 | + dev->name, ret); | |
188 | + return ret; | |
189 | + } | |
190 | + | |
191 | + priv->state = false; | |
192 | + | |
193 | + return 0; | |
194 | +} | |
195 | + | |
196 | +static const struct udevice_id gdsys_ioep_ids[] = { | |
197 | + { .compatible = "gdsys,io-endpoint" }, | |
198 | + { } | |
199 | +}; | |
200 | + | |
201 | +U_BOOT_DRIVER(gdsys_ioep) = { | |
202 | + .name = "gdsys_ioep", | |
203 | + .id = UCLASS_MISC, | |
204 | + .ops = &gdsys_ioep_ops, | |
205 | + .flags = DM_UC_FLAG_SEQ_ALIAS, | |
206 | + .of_match = gdsys_ioep_ids, | |
207 | + .probe = gdsys_ioep_probe, | |
208 | + .priv_auto_alloc_size = sizeof(struct gdsys_ioep_priv), | |
209 | +}; |
drivers/misc/gdsys_ioep.h
1 | +/* SPDX-License-Identifier: GPL-2.0+ */ | |
2 | +/* | |
3 | + * (C) Copyright 2018 | |
4 | + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc | |
5 | + */ | |
6 | + | |
7 | +#ifndef __GDSYS_IOEP_H_ | |
8 | +#define __GDSYS_IOEP_H_ | |
9 | + | |
10 | +/** | |
11 | + * struct io_generic_packet - header structure for GDSYS IOEP packets | |
12 | + * @target_address: Target protocol address of the packet. | |
13 | + * @source_address: Source protocol address of the packet. | |
14 | + * @packet_type: Packet type. | |
15 | + * @bc: Block counter (filled in by FPGA). | |
16 | + * @packet_length: Length of the packet's payload bytes. | |
17 | + */ | |
18 | +struct io_generic_packet { | |
19 | + u16 target_address; | |
20 | + u16 source_address; | |
21 | + u8 packet_type; | |
22 | + u8 bc; | |
23 | + u16 packet_length; | |
24 | +} __attribute__((__packed__)); | |
25 | + | |
26 | +/** | |
27 | + * struct gdsys_ioep_regs - Registers of a IOEP device | |
28 | + * @transmit_data: Register that receives data to be sent | |
29 | + * @tx_control: TX control register | |
30 | + * @receive_data: Register filled with the received data | |
31 | + * @rx_tx_status: RX/TX status register | |
32 | + * @device_address: Register for setting/reading the device's address | |
33 | + * @target_address: Register for setting/reading the remote endpoint's address | |
34 | + * @int_enable: Interrupt/Interrupt enable register | |
35 | + */ | |
36 | +struct gdsys_ioep_regs { | |
37 | + u16 transmit_data; | |
38 | + u16 tx_control; | |
39 | + u16 receive_data; | |
40 | + u16 rx_tx_status; | |
41 | + u16 device_address; | |
42 | + u16 target_address; | |
43 | + u16 int_enable; | |
44 | +}; | |
45 | + | |
46 | +/** | |
47 | + * gdsys_ioep_set() - Convenience macro to write registers of a IOEP device | |
48 | + * @map: Register map to write the value in | |
49 | + * @member: Name of the member in the gdsys_ioep_regs structure to write | |
50 | + * @val: Value to write to the register | |
51 | + */ | |
52 | +#define gdsys_ioep_set(map, member, val) \ | |
53 | + regmap_set(map, struct gdsys_ioep_regs, member, val) | |
54 | + | |
55 | +/** | |
56 | + * gdsys_ioep_get() - Convenience macro to read registers of a IOEP device | |
57 | + * @map: Register map to read the value from | |
58 | + * @member: Name of the member in the gdsys_ioep_regs structure to read | |
59 | + * @valp: Pointer to buffer to read the register value into | |
60 | + */ | |
61 | +#define gdsys_ioep_get(map, member, valp) \ | |
62 | + regmap_get(map, struct gdsys_ioep_regs, member, valp) | |
63 | + | |
64 | +/** | |
65 | + * enum rx_tx_status_values - Enum to describe the fields of the rx_tx_status | |
66 | + * register | |
67 | + * @STATE_TX_PACKET_BUILDING: The device is currently building a packet | |
68 | + * (and accepting data for it) | |
69 | + * @STATE_TX_TRANSMITTING: A packet is currenly being transmitted | |
70 | + * @STATE_TX_BUFFER_FULL: The TX buffer is full | |
71 | + * @STATE_TX_ERR: A TX error occurred | |
72 | + * @STATE_RECEIVE_TIMEOUT: A receive timeout occurred | |
73 | + * @STATE_PROC_RX_STORE_TIMEOUT: A RX store timeout for a processor packet | |
74 | + * occurred | |
75 | + * @STATE_PROC_RX_RECEIVE_TIMEOUT: A RX receive timeout for a processor packet | |
76 | + * occurred | |
77 | + * @STATE_RX_DIST_ERR: A error occurred in the distribution block | |
78 | + * @STATE_RX_LENGTH_ERR: A length invalid error occurred | |
79 | + * @STATE_RX_FRAME_CTR_ERR: A frame count error occurred (two | |
80 | + * non-increasing frame count numbers | |
81 | + * encountered) | |
82 | + * @STATE_RX_FCS_ERR: A CRC error occurred | |
83 | + * @STATE_RX_PACKET_DROPPED: A RX packet has been dropped | |
84 | + * @STATE_RX_DATA_LAST: The data to be read is the final data of the | |
85 | + * current packet | |
86 | + * @STATE_RX_DATA_FIRST: The data to be read is the first data of the | |
87 | + * current packet | |
88 | + * @STATE_RX_DATA_AVAILABLE: RX data is available to be read | |
89 | + */ | |
90 | +enum rx_tx_status_values { | |
91 | + STATE_TX_PACKET_BUILDING = BIT(0), | |
92 | + STATE_TX_TRANSMITTING = BIT(1), | |
93 | + STATE_TX_BUFFER_FULL = BIT(2), | |
94 | + STATE_TX_ERR = BIT(3), | |
95 | + STATE_RECEIVE_TIMEOUT = BIT(4), | |
96 | + STATE_PROC_RX_STORE_TIMEOUT = BIT(5), | |
97 | + STATE_PROC_RX_RECEIVE_TIMEOUT = BIT(6), | |
98 | + STATE_RX_DIST_ERR = BIT(7), | |
99 | + STATE_RX_LENGTH_ERR = BIT(8), | |
100 | + STATE_RX_FRAME_CTR_ERR = BIT(9), | |
101 | + STATE_RX_FCS_ERR = BIT(10), | |
102 | + STATE_RX_PACKET_DROPPED = BIT(11), | |
103 | + STATE_RX_DATA_LAST = BIT(12), | |
104 | + STATE_RX_DATA_FIRST = BIT(13), | |
105 | + STATE_RX_DATA_AVAILABLE = BIT(15), | |
106 | +}; | |
107 | + | |
108 | +/** | |
109 | + * enum tx_control_values - Enum to describe the fields of the tx_control | |
110 | + * register | |
111 | + * @CTRL_PROC_RECEIVE_ENABLE: Enable packet reception for the processor | |
112 | + * @CTRL_FLUSH_TRANSMIT_BUFFER: Flush the transmit buffer (and send packet data) | |
113 | + */ | |
114 | +enum tx_control_values { | |
115 | + CTRL_PROC_RECEIVE_ENABLE = BIT(12), | |
116 | + CTRL_FLUSH_TRANSMIT_BUFFER = BIT(15), | |
117 | +}; | |
118 | + | |
119 | +/** | |
120 | + * enum int_enable_values - Enum to describe the fields of the int_enable | |
121 | + * register | |
122 | + * @IRQ_CPU_TRANSMITBUFFER_FREE_STATUS: The transmit buffer is free (packet | |
123 | + * data can be transmitted to the | |
124 | + * device) | |
125 | + * @IRQ_CPU_PACKET_TRANSMITTED_EVENT: A packet has been transmitted | |
126 | + * @IRQ_NEW_CPU_PACKET_RECEIVED_EVENT: A new packet has been received | |
127 | + * @IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS: RX packet data are available to be | |
128 | + * read | |
129 | + */ | |
130 | +enum int_enable_values { | |
131 | + IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = BIT(5), | |
132 | + IRQ_CPU_PACKET_TRANSMITTED_EVENT = BIT(6), | |
133 | + IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = BIT(7), | |
134 | + IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = BIT(8), | |
135 | +}; | |
136 | + | |
137 | +#endif /* __GDSYS_IOEP_H_ */ |
drivers/misc/misc-uclass.c
... | ... | @@ -55,6 +55,16 @@ |
55 | 55 | return ops->call(dev, msgid, tx_msg, tx_size, rx_msg, rx_size); |
56 | 56 | } |
57 | 57 | |
58 | +int misc_set_enabled(struct udevice *dev, bool val) | |
59 | +{ | |
60 | + const struct misc_ops *ops = device_get_ops(dev); | |
61 | + | |
62 | + if (!ops->set_enabled) | |
63 | + return -ENOSYS; | |
64 | + | |
65 | + return ops->set_enabled(dev, val); | |
66 | +} | |
67 | + | |
58 | 68 | UCLASS_DRIVER(misc) = { |
59 | 69 | .id = UCLASS_MISC, |
60 | 70 | .name = "misc", |
drivers/misc/misc_sandbox.c
1 | +// SPDX-License-Identifier: GPL-2.0+ | |
2 | +/* | |
3 | + * (C) Copyright 2018 | |
4 | + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <dm.h> | |
9 | +#include <misc.h> | |
10 | + | |
11 | +struct misc_sandbox_priv { | |
12 | + u8 mem[128]; | |
13 | + ulong last_ioctl; | |
14 | + bool enabled; | |
15 | +}; | |
16 | + | |
17 | +int misc_sandbox_read(struct udevice *dev, int offset, void *buf, int size) | |
18 | +{ | |
19 | + struct misc_sandbox_priv *priv = dev_get_priv(dev); | |
20 | + | |
21 | + memcpy(buf, priv->mem + offset, size); | |
22 | + | |
23 | + return 0; | |
24 | +} | |
25 | + | |
26 | +int misc_sandbox_write(struct udevice *dev, int offset, const void *buf, | |
27 | + int size) | |
28 | +{ | |
29 | + struct misc_sandbox_priv *priv = dev_get_priv(dev); | |
30 | + | |
31 | + memcpy(priv->mem + offset, buf, size); | |
32 | + | |
33 | + return 0; | |
34 | +} | |
35 | + | |
36 | +int misc_sandbox_ioctl(struct udevice *dev, unsigned long request, void *buf) | |
37 | +{ | |
38 | + struct misc_sandbox_priv *priv = dev_get_priv(dev); | |
39 | + | |
40 | + priv->last_ioctl = request; | |
41 | + | |
42 | + return 0; | |
43 | +} | |
44 | + | |
45 | +int misc_sandbox_call(struct udevice *dev, int msgid, void *tx_msg, | |
46 | + int tx_size, void *rx_msg, int rx_size) | |
47 | +{ | |
48 | + struct misc_sandbox_priv *priv = dev_get_priv(dev); | |
49 | + | |
50 | + if (msgid == 0) { | |
51 | + int num = *(int *)tx_msg; | |
52 | + | |
53 | + switch (num) { | |
54 | + case 0: | |
55 | + strncpy(rx_msg, "Zero", rx_size); | |
56 | + break; | |
57 | + case 1: | |
58 | + strncpy(rx_msg, "One", rx_size); | |
59 | + break; | |
60 | + case 2: | |
61 | + strncpy(rx_msg, "Two", rx_size); | |
62 | + break; | |
63 | + default: | |
64 | + return -EINVAL; | |
65 | + } | |
66 | + } | |
67 | + | |
68 | + if (msgid == 1) { | |
69 | + int num = *(int *)tx_msg; | |
70 | + | |
71 | + switch (num) { | |
72 | + case 0: | |
73 | + strncpy(rx_msg, "Forty", rx_size); | |
74 | + break; | |
75 | + case 1: | |
76 | + strncpy(rx_msg, "Forty-one", rx_size); | |
77 | + break; | |
78 | + case 2: | |
79 | + strncpy(rx_msg, "Forty-two", rx_size); | |
80 | + break; | |
81 | + default: | |
82 | + return -EINVAL; | |
83 | + } | |
84 | + } | |
85 | + | |
86 | + if (msgid == 2) | |
87 | + memcpy(rx_msg, &priv->last_ioctl, sizeof(priv->last_ioctl)); | |
88 | + | |
89 | + if (msgid == 3) | |
90 | + memcpy(rx_msg, &priv->enabled, sizeof(priv->enabled)); | |
91 | + | |
92 | + return 0; | |
93 | +} | |
94 | + | |
95 | +int misc_sandbox_set_enabled(struct udevice *dev, bool val) | |
96 | +{ | |
97 | + struct misc_sandbox_priv *priv = dev_get_priv(dev); | |
98 | + | |
99 | + priv->enabled = !priv->enabled; | |
100 | + | |
101 | + return 0; | |
102 | +} | |
103 | + | |
104 | +static const struct misc_ops misc_sandbox_ops = { | |
105 | + .read = misc_sandbox_read, | |
106 | + .write = misc_sandbox_write, | |
107 | + .ioctl = misc_sandbox_ioctl, | |
108 | + .call = misc_sandbox_call, | |
109 | + .set_enabled = misc_sandbox_set_enabled, | |
110 | +}; | |
111 | + | |
112 | +int misc_sandbox_probe(struct udevice *dev) | |
113 | +{ | |
114 | + struct misc_sandbox_priv *priv = dev_get_priv(dev); | |
115 | + | |
116 | + priv->enabled = true; | |
117 | + | |
118 | + return 0; | |
119 | +} | |
120 | + | |
121 | +static const struct udevice_id misc_sandbox_ids[] = { | |
122 | + { .compatible = "sandbox,misc_sandbox" }, | |
123 | + { } | |
124 | +}; | |
125 | + | |
126 | +U_BOOT_DRIVER(misc_sandbox) = { | |
127 | + .name = "misc_sandbox", | |
128 | + .id = UCLASS_MISC, | |
129 | + .ops = &misc_sandbox_ops, | |
130 | + .of_match = misc_sandbox_ids, | |
131 | + .probe = misc_sandbox_probe, | |
132 | + .priv_auto_alloc_size = sizeof(struct misc_sandbox_priv), | |
133 | +}; |
include/misc.h
... | ... | @@ -6,38 +6,47 @@ |
6 | 6 | #ifndef _MISC_H_ |
7 | 7 | #define _MISC_H_ |
8 | 8 | |
9 | -/* | |
10 | - * Read the device to buffer, optional. | |
11 | - * | |
9 | +/** | |
10 | + * misc_read() - Read the device to buffer, optional. | |
12 | 11 | * @dev: the device |
13 | 12 | * @offset: offset to read the device |
14 | 13 | * @buf: pointer to data buffer |
15 | 14 | * @size: data size in bytes to read the device |
16 | - * @return: 0 if OK, -ve on error | |
15 | + * | |
16 | + * Return: 0 if OK, -ve on error | |
17 | 17 | */ |
18 | 18 | int misc_read(struct udevice *dev, int offset, void *buf, int size); |
19 | -/* | |
20 | - * Write buffer to the device, optional. | |
21 | - * | |
19 | + | |
20 | +/** | |
21 | + * misc_write() - Write buffer to the device, optional. | |
22 | 22 | * @dev: the device |
23 | 23 | * @offset: offset to write the device |
24 | 24 | * @buf: pointer to data buffer |
25 | 25 | * @size: data size in bytes to write the device |
26 | - * @return: 0 if OK, -ve on error | |
26 | + * | |
27 | + * Return: 0 if OK, -ve on error | |
27 | 28 | */ |
28 | 29 | int misc_write(struct udevice *dev, int offset, void *buf, int size); |
29 | -/* | |
30 | - * Assert command to the device, optional. | |
31 | - * | |
30 | + | |
31 | +/** | |
32 | + * misc_ioctl() - Assert command to the device, optional. | |
32 | 33 | * @dev: the device |
33 | 34 | * @request: command to be sent to the device |
34 | 35 | * @buf: pointer to buffer related to the request |
35 | - * @return: 0 if OK, -ve on error | |
36 | + * | |
37 | + * Return: 0 if OK, -ve on error | |
36 | 38 | */ |
37 | 39 | int misc_ioctl(struct udevice *dev, unsigned long request, void *buf); |
38 | 40 | |
39 | -/* | |
40 | - * Send a message to the device and wait for a response. | |
41 | +/** | |
42 | + * misc_call() - Send a message to the device and wait for a response. | |
43 | + * @dev: the device. | |
44 | + * @msgid: the message ID/number to send. | |
45 | + * @tx_msg: the request/transmit message payload. | |
46 | + * @tx_size: the size of the buffer pointed at by tx_msg. | |
47 | + * @rx_msg: the buffer to receive the response message payload. May be NULL if | |
48 | + * the caller only cares about the error code. | |
49 | + * @rx_size: the size of the buffer pointed at by rx_msg. | |
41 | 50 | * |
42 | 51 | * The caller provides the message type/ID and payload to be sent. |
43 | 52 | * The callee constructs any message header required, transmits it to the |
44 | 53 | |
... | ... | @@ -45,18 +54,28 @@ |
45 | 54 | * strips any message header from the response, and returns the error code |
46 | 55 | * (or a parsed version of it) and the response message payload. |
47 | 56 | * |
48 | - * @dev: the device. | |
49 | - * @msgid: the message ID/number to send. | |
50 | - * tx_msg: the request/transmit message payload. | |
51 | - * tx_size: the size of the buffer pointed at by tx_msg. | |
52 | - * rx_msg: the buffer to receive the response message payload. May be NULL if | |
53 | - * the caller only cares about the error code. | |
54 | - * rx_size: the size of the buffer pointed at by rx_msg. | |
55 | - * @return the response message size if OK, -ve on error | |
57 | + * Return: the response message size if OK, -ve on error | |
56 | 58 | */ |
57 | 59 | int misc_call(struct udevice *dev, int msgid, void *tx_msg, int tx_size, |
58 | 60 | void *rx_msg, int rx_size); |
59 | 61 | |
62 | +/** | |
63 | + * misc_set_enabled() - Enable or disable a device. | |
64 | + * @dev: the device to enable or disable. | |
65 | + * @val: the flag that tells the driver to either enable or disable the device. | |
66 | + * | |
67 | + * The semantics of "disable" and "enable" should be understood here as | |
68 | + * activating or deactivating the device's primary function, hence a "disabled" | |
69 | + * device should be dormant, but still answer to commands and queries. | |
70 | + * | |
71 | + * A probed device may start in a disabled or enabled state, depending on the | |
72 | + * driver and hardware. | |
73 | + * | |
74 | + * Return: -ve on error, 0 if the previous state was "disabled", 1 if the | |
75 | + * previous state was "enabled" | |
76 | + */ | |
77 | +int misc_set_enabled(struct udevice *dev, bool val); | |
78 | + | |
60 | 79 | /* |
61 | 80 | * struct misc_ops - Driver model Misc operations |
62 | 81 | * |
63 | 82 | |
64 | 83 | |
65 | 84 | |
66 | 85 | |
67 | 86 | |
68 | 87 | |
69 | 88 | |
70 | 89 | |
71 | 90 | |
72 | 91 | |
73 | 92 | |
74 | 93 | |
... | ... | @@ -64,50 +83,62 @@ |
64 | 83 | * use driver model. |
65 | 84 | */ |
66 | 85 | struct misc_ops { |
67 | - /* | |
86 | + /** | |
68 | 87 | * Read the device to buffer, optional. |
69 | - * | |
70 | 88 | * @dev: the device |
71 | 89 | * @offset: offset to read the device |
72 | 90 | * @buf: pointer to data buffer |
73 | 91 | * @size: data size in bytes to read the device |
74 | - * @return: 0 if OK, -ve on error | |
92 | + * | |
93 | + * Return: 0 if OK, -ve on error | |
75 | 94 | */ |
76 | 95 | int (*read)(struct udevice *dev, int offset, void *buf, int size); |
77 | - /* | |
96 | + | |
97 | + /** | |
78 | 98 | * Write buffer to the device, optional. |
79 | - * | |
80 | 99 | * @dev: the device |
81 | 100 | * @offset: offset to write the device |
82 | 101 | * @buf: pointer to data buffer |
83 | 102 | * @size: data size in bytes to write the device |
84 | - * @return: 0 if OK, -ve on error | |
103 | + * | |
104 | + * Return: 0 if OK, -ve on error | |
85 | 105 | */ |
86 | 106 | int (*write)(struct udevice *dev, int offset, const void *buf, |
87 | 107 | int size); |
88 | - /* | |
108 | + /** | |
89 | 109 | * Assert command to the device, optional. |
90 | - * | |
91 | 110 | * @dev: the device |
92 | 111 | * @request: command to be sent to the device |
93 | 112 | * @buf: pointer to buffer related to the request |
94 | - * @return: 0 if OK, -ve on error | |
113 | + * | |
114 | + * Return: 0 if OK, -ve on error | |
95 | 115 | */ |
96 | 116 | int (*ioctl)(struct udevice *dev, unsigned long request, void *buf); |
97 | - /* | |
117 | + | |
118 | + /** | |
98 | 119 | * Send a message to the device and wait for a response. |
99 | - * | |
100 | 120 | * @dev: the device |
101 | 121 | * @msgid: the message ID/number to send |
102 | - * tx_msg: the request/transmit message payload | |
103 | - * tx_size: the size of the buffer pointed at by tx_msg | |
104 | - * rx_msg: the buffer to receive the response message payload. May be | |
105 | - * NULL if the caller only cares about the error code. | |
106 | - * rx_size: the size of the buffer pointed at by rx_msg | |
107 | - * @return the response message size if OK, -ve on error | |
122 | + * @tx_msg: the request/transmit message payload | |
123 | + * @tx_size: the size of the buffer pointed at by tx_msg | |
124 | + * @rx_msg: the buffer to receive the response message payload. May be | |
125 | + * NULL if the caller only cares about the error code. | |
126 | + * @rx_size: the size of the buffer pointed at by rx_msg | |
127 | + * | |
128 | + * Return: the response message size if OK, -ve on error | |
108 | 129 | */ |
109 | 130 | int (*call)(struct udevice *dev, int msgid, void *tx_msg, int tx_size, |
110 | 131 | void *rx_msg, int rx_size); |
132 | + /** | |
133 | + * Enable or disable a device, optional. | |
134 | + * @dev: the device to enable. | |
135 | + * @val: the flag that tells the driver to either enable or disable the | |
136 | + * device. | |
137 | + * | |
138 | + * Return: -ve on error, 0 if the previous state was "disabled", 1 if | |
139 | + * the previous state was "enabled" | |
140 | + */ | |
141 | + int (*set_enabled)(struct udevice *dev, bool val); | |
111 | 142 | }; |
112 | 143 | |
113 | 144 | #endif /* _MISC_H_ */ |
test/dm/Makefile
test/dm/misc.c
1 | +// SPDX-License-Identifier: GPL-2.0+ | |
2 | +/* | |
3 | + * (C) Copyright 2018 | |
4 | + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <dm.h> | |
9 | +#include <dm/test.h> | |
10 | +#include <misc.h> | |
11 | +#include <test/ut.h> | |
12 | + | |
13 | +static int dm_test_misc(struct unit_test_state *uts) | |
14 | +{ | |
15 | + struct udevice *dev; | |
16 | + u8 buf[16]; | |
17 | + int id; | |
18 | + ulong last_ioctl; | |
19 | + bool enabled; | |
20 | + | |
21 | + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "misc-test", &dev)); | |
22 | + | |
23 | + /* Read / write tests */ | |
24 | + ut_assertok(misc_write(dev, 0, "TEST", 4)); | |
25 | + ut_assertok(misc_write(dev, 4, "WRITE", 5)); | |
26 | + ut_assertok(misc_read(dev, 0, buf, 9)); | |
27 | + | |
28 | + ut_assertok(memcmp(buf, "TESTWRITE", 9)); | |
29 | + | |
30 | + /* Call tests */ | |
31 | + | |
32 | + id = 0; | |
33 | + ut_assertok(misc_call(dev, 0, &id, 4, buf, 16)); | |
34 | + ut_assertok(memcmp(buf, "Zero", 4)); | |
35 | + | |
36 | + id = 2; | |
37 | + ut_assertok(misc_call(dev, 0, &id, 4, buf, 16)); | |
38 | + ut_assertok(memcmp(buf, "Two", 3)); | |
39 | + | |
40 | + ut_assertok(misc_call(dev, 1, &id, 4, buf, 16)); | |
41 | + ut_assertok(memcmp(buf, "Forty-two", 9)); | |
42 | + | |
43 | + id = 1; | |
44 | + ut_assertok(misc_call(dev, 1, &id, 4, buf, 16)); | |
45 | + ut_assertok(memcmp(buf, "Forty-one", 9)); | |
46 | + | |
47 | + /* IOCTL tests */ | |
48 | + | |
49 | + ut_assertok(misc_ioctl(dev, 6, NULL)); | |
50 | + /* Read back last issued ioctl */ | |
51 | + ut_assertok(misc_call(dev, 2, NULL, 0, &last_ioctl, | |
52 | + sizeof(last_ioctl))); | |
53 | + ut_asserteq(6, last_ioctl) | |
54 | + | |
55 | + ut_assertok(misc_ioctl(dev, 23, NULL)); | |
56 | + /* Read back last issued ioctl */ | |
57 | + ut_assertok(misc_call(dev, 2, NULL, 0, &last_ioctl, | |
58 | + sizeof(last_ioctl))); | |
59 | + ut_asserteq(23, last_ioctl) | |
60 | + | |
61 | + /* Enable / disable tests */ | |
62 | + | |
63 | + /* Read back enable/disable status */ | |
64 | + ut_assertok(misc_call(dev, 3, NULL, 0, &enabled, | |
65 | + sizeof(enabled))); | |
66 | + ut_asserteq(true, enabled); | |
67 | + | |
68 | + ut_assertok(misc_set_enabled(dev, false)); | |
69 | + /* Read back enable/disable status */ | |
70 | + ut_assertok(misc_call(dev, 3, NULL, 0, &enabled, | |
71 | + sizeof(enabled))); | |
72 | + ut_asserteq(false, enabled); | |
73 | + | |
74 | + ut_assertok(misc_set_enabled(dev, true)); | |
75 | + /* Read back enable/disable status */ | |
76 | + ut_assertok(misc_call(dev, 3, NULL, 0, &enabled, | |
77 | + sizeof(enabled))); | |
78 | + ut_asserteq(true, enabled); | |
79 | + | |
80 | + return 0; | |
81 | +} | |
82 | + | |
83 | +DM_TEST(dm_test_misc, DM_TESTF_SCAN_FDT); |