mbox.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * (C) Copyright 2012 Stephen Warren
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <common.h>
  7. #include <asm/io.h>
  8. #include <asm/arch/mbox.h>
  9. #define TIMEOUT (100 * 1000) /* 100mS in uS */
  10. int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
  11. {
  12. struct bcm2835_mbox_regs *regs =
  13. (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
  14. ulong endtime = get_timer(0) + TIMEOUT;
  15. u32 val;
  16. debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
  17. if (send & BCM2835_CHAN_MASK) {
  18. printf("mbox: Illegal mbox data 0x%08x\n", send);
  19. return -1;
  20. }
  21. /* Drain any stale responses */
  22. for (;;) {
  23. val = readl(&regs->status);
  24. if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
  25. break;
  26. if (get_timer(0) >= endtime) {
  27. printf("mbox: Timeout draining stale responses\n");
  28. return -1;
  29. }
  30. val = readl(&regs->read);
  31. }
  32. /* Wait for space to send */
  33. for (;;) {
  34. val = readl(&regs->status);
  35. if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
  36. break;
  37. if (get_timer(0) >= endtime) {
  38. printf("mbox: Timeout waiting for send space\n");
  39. return -1;
  40. }
  41. }
  42. /* Send the request */
  43. val = BCM2835_MBOX_PACK(chan, send);
  44. debug("mbox: TX raw: 0x%08x\n", val);
  45. writel(val, &regs->write);
  46. /* Wait for the response */
  47. for (;;) {
  48. val = readl(&regs->status);
  49. if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
  50. break;
  51. if (get_timer(0) >= endtime) {
  52. printf("mbox: Timeout waiting for response\n");
  53. return -1;
  54. }
  55. }
  56. /* Read the response */
  57. val = readl(&regs->read);
  58. debug("mbox: RX raw: 0x%08x\n", val);
  59. /* Validate the response */
  60. if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
  61. printf("mbox: Response channel mismatch\n");
  62. return -1;
  63. }
  64. *recv = BCM2835_MBOX_UNPACK_DATA(val);
  65. return 0;
  66. }
  67. #ifdef DEBUG
  68. void dump_buf(struct bcm2835_mbox_hdr *buffer)
  69. {
  70. u32 *p;
  71. u32 words;
  72. int i;
  73. p = (u32 *)buffer;
  74. words = buffer->buf_size / 4;
  75. for (i = 0; i < words; i++)
  76. printf(" 0x%04x: 0x%08x\n", i * 4, p[i]);
  77. }
  78. #endif
  79. int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
  80. {
  81. int ret;
  82. u32 rbuffer;
  83. struct bcm2835_mbox_tag_hdr *tag;
  84. int tag_index;
  85. #ifdef DEBUG
  86. printf("mbox: TX buffer\n");
  87. dump_buf(buffer);
  88. #endif
  89. ret = bcm2835_mbox_call_raw(chan, (u32)buffer, &rbuffer);
  90. if (ret)
  91. return ret;
  92. if (rbuffer != (u32)buffer) {
  93. printf("mbox: Response buffer mismatch\n");
  94. return -1;
  95. }
  96. #ifdef DEBUG
  97. printf("mbox: RX buffer\n");
  98. dump_buf(buffer);
  99. #endif
  100. /* Validate overall response status */
  101. if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
  102. printf("mbox: Header response code invalid\n");
  103. return -1;
  104. }
  105. /* Validate each tag's response status */
  106. tag = (void *)(buffer + 1);
  107. tag_index = 0;
  108. while (tag->tag) {
  109. if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
  110. printf("mbox: Tag %d missing val_len response bit\n",
  111. tag_index);
  112. return -1;
  113. }
  114. /*
  115. * Clear the reponse bit so clients can just look right at the
  116. * length field without extra processing
  117. */
  118. tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
  119. tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
  120. tag_index++;
  121. }
  122. return 0;
  123. }