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 }; 210