gdsys_ioep.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. #include <common.h>
  14. #include <dm.h>
  15. #include <log.h>
  16. #include <misc.h>
  17. #include <regmap.h>
  18. #include "gdsys_ioep.h"
  19. /**
  20. * struct gdsys_ioep_priv - Private data structure for IOEP devices
  21. * @map: Register map to be used for the device
  22. * @state: Flag to keep the current status of the RX control (enabled/disabled)
  23. */
  24. struct gdsys_ioep_priv {
  25. struct regmap *map;
  26. bool state;
  27. };
  28. /**
  29. * enum last_spec - Convenience enum for read data sanity check
  30. * @READ_DATA_IS_LAST: The data to be read should be the final data of the
  31. * current packet
  32. * @READ_DATA_IS_NOT_LAST: The data to be read should not be the final data of
  33. * the current packet
  34. */
  35. enum last_spec {
  36. READ_DATA_IS_LAST,
  37. READ_DATA_IS_NOT_LAST,
  38. };
  39. static int gdsys_ioep_set_receive(struct udevice *dev, bool val)
  40. {
  41. struct gdsys_ioep_priv *priv = dev_get_priv(dev);
  42. u16 state;
  43. priv->state = !priv->state;
  44. if (val)
  45. state = CTRL_PROC_RECEIVE_ENABLE;
  46. else
  47. state = ~CTRL_PROC_RECEIVE_ENABLE;
  48. gdsys_ioep_set(priv->map, tx_control, state);
  49. if (val) {
  50. /* Set device address to dummy 1 */
  51. gdsys_ioep_set(priv->map, device_address, 1);
  52. }
  53. return !priv->state;
  54. }
  55. static int gdsys_ioep_send(struct udevice *dev, int offset,
  56. const void *buf, int size)
  57. {
  58. struct gdsys_ioep_priv *priv = dev_get_priv(dev);
  59. int k;
  60. u16 *p = (u16 *)buf;
  61. for (k = 0; k < size; ++k)
  62. gdsys_ioep_set(priv->map, transmit_data, *(p++));
  63. gdsys_ioep_set(priv->map, tx_control, CTRL_PROC_RECEIVE_ENABLE |
  64. CTRL_FLUSH_TRANSMIT_BUFFER);
  65. return 0;
  66. }
  67. /**
  68. * receive_byte_buffer() - Read data from a IOEP device
  69. * @dev: The IOEP device to read data from
  70. * @len: The length of the data to read
  71. * @buffer: The buffer to read the data into
  72. * @last_spec: Flag to indicate if the data to be read in this call should be
  73. * the final data of the current packet (i.e. it should be empty
  74. * after this read)
  75. *
  76. * Return: 0 if OK, -ve on error
  77. */
  78. static int receive_byte_buffer(struct udevice *dev, uint len,
  79. u16 *buffer, enum last_spec last_spec)
  80. {
  81. struct gdsys_ioep_priv *priv = dev_get_priv(dev);
  82. int k;
  83. int ret = -EIO;
  84. for (k = 0; k < len; ++k) {
  85. u16 rx_tx_status;
  86. gdsys_ioep_get(priv->map, receive_data, buffer++);
  87. gdsys_ioep_get(priv->map, rx_tx_status, &rx_tx_status);
  88. /*
  89. * Sanity check: If the data read should have been the last,
  90. * but wasn't, something is wrong
  91. */
  92. if (k == (len - 1) && (last_spec == READ_DATA_IS_NOT_LAST ||
  93. rx_tx_status & STATE_RX_DATA_LAST))
  94. ret = 0;
  95. }
  96. if (ret)
  97. debug("%s: Error while receiving bufer (err = %d)\n",
  98. dev->name, ret);
  99. return ret;
  100. }
  101. static int gdsys_ioep_receive(struct udevice *dev, int offset, void *buf,
  102. int size)
  103. {
  104. int ret;
  105. struct io_generic_packet header;
  106. u16 *p = (u16 *)buf;
  107. const int header_words = sizeof(struct io_generic_packet) / sizeof(u16);
  108. uint len;
  109. /* Read the packet header */
  110. ret = receive_byte_buffer(dev, header_words, p, READ_DATA_IS_NOT_LAST);
  111. if (ret) {
  112. debug("%s: Failed to read header data (err = %d)\n",
  113. dev->name, ret);
  114. return ret;
  115. }
  116. memcpy(&header, p, header_words * sizeof(u16));
  117. p += header_words;
  118. /* Get payload data length */
  119. len = (header.packet_length + 1) / sizeof(u16);
  120. /* Read the packet payload */
  121. ret = receive_byte_buffer(dev, len, p, READ_DATA_IS_LAST);
  122. if (ret) {
  123. debug("%s: Failed to read payload data (err = %d)\n",
  124. dev->name, ret);
  125. return ret;
  126. }
  127. return 0;
  128. }
  129. static int gdsys_ioep_get_and_reset_status(struct udevice *dev, int msgid,
  130. void *tx_msg, int tx_size,
  131. void *rx_msg, int rx_size)
  132. {
  133. struct gdsys_ioep_priv *priv = dev_get_priv(dev);
  134. const u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR |
  135. STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR |
  136. STATE_RX_PACKET_DROPPED | STATE_TX_ERR;
  137. u16 *status = rx_msg;
  138. gdsys_ioep_get(priv->map, rx_tx_status, status);
  139. gdsys_ioep_set(priv->map, rx_tx_status, *status);
  140. return (*status & mask) ? 1 : 0;
  141. }
  142. static const struct misc_ops gdsys_ioep_ops = {
  143. .set_enabled = gdsys_ioep_set_receive,
  144. .write = gdsys_ioep_send,
  145. .read = gdsys_ioep_receive,
  146. .call = gdsys_ioep_get_and_reset_status,
  147. };
  148. static int gdsys_ioep_probe(struct udevice *dev)
  149. {
  150. struct gdsys_ioep_priv *priv = dev_get_priv(dev);
  151. int ret;
  152. ret = regmap_init_mem(dev_ofnode(dev), &priv->map);
  153. if (ret) {
  154. debug("%s: Could not initialize regmap (err = %d)",
  155. dev->name, ret);
  156. return ret;
  157. }
  158. priv->state = false;
  159. return 0;
  160. }
  161. static const struct udevice_id gdsys_ioep_ids[] = {
  162. { .compatible = "gdsys,io-endpoint" },
  163. { }
  164. };
  165. U_BOOT_DRIVER(gdsys_ioep) = {
  166. .name = "gdsys_ioep",
  167. .id = UCLASS_MISC,
  168. .ops = &gdsys_ioep_ops,
  169. .flags = DM_UC_FLAG_SEQ_ALIAS,
  170. .of_match = gdsys_ioep_ids,
  171. .probe = gdsys_ioep_probe,
  172. .priv_auto_alloc_size = sizeof(struct gdsys_ioep_priv),
  173. };