mbox.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * (C) Copyright 2012 Stephen Warren
  3. *
  4. * See file CREDITS for list of people who contributed to this
  5. * project.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. */
  17. #include <common.h>
  18. #include <asm/io.h>
  19. #include <asm/arch/mbox.h>
  20. #define TIMEOUT (100 * 1000) /* 100mS in uS */
  21. int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
  22. {
  23. struct bcm2835_mbox_regs *regs =
  24. (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
  25. ulong endtime = get_timer(0) + TIMEOUT;
  26. u32 val;
  27. debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
  28. if (send & BCM2835_CHAN_MASK) {
  29. printf("mbox: Illegal mbox data 0x%08x\n", send);
  30. return -1;
  31. }
  32. /* Drain any stale responses */
  33. for (;;) {
  34. val = readl(&regs->status);
  35. if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
  36. break;
  37. if (get_timer(0) >= endtime) {
  38. printf("mbox: Timeout draining stale responses\n");
  39. return -1;
  40. }
  41. val = readl(&regs->read);
  42. }
  43. /* Wait for space to send */
  44. for (;;) {
  45. val = readl(&regs->status);
  46. if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
  47. break;
  48. if (get_timer(0) >= endtime) {
  49. printf("mbox: Timeout waiting for send space\n");
  50. return -1;
  51. }
  52. }
  53. /* Send the request */
  54. val = BCM2835_MBOX_PACK(chan, send);
  55. debug("mbox: TX raw: 0x%08x\n", val);
  56. writel(val, &regs->write);
  57. /* Wait for the response */
  58. for (;;) {
  59. val = readl(&regs->status);
  60. if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
  61. break;
  62. if (get_timer(0) >= endtime) {
  63. printf("mbox: Timeout waiting for response\n");
  64. return -1;
  65. }
  66. }
  67. /* Read the response */
  68. val = readl(&regs->read);
  69. debug("mbox: RX raw: 0x%08x\n", val);
  70. /* Validate the response */
  71. if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
  72. printf("mbox: Response channel mismatch\n");
  73. return -1;
  74. }
  75. *recv = BCM2835_MBOX_UNPACK_DATA(val);
  76. return 0;
  77. }
  78. #ifdef DEBUG
  79. void dump_buf(struct bcm2835_mbox_hdr *buffer)
  80. {
  81. u32 *p;
  82. u32 words;
  83. int i;
  84. p = (u32 *)buffer;
  85. words = buffer->buf_size / 4;
  86. for (i = 0; i < words; i++)
  87. printf(" 0x%04x: 0x%08x\n", i * 4, p[i]);
  88. }
  89. #endif
  90. int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
  91. {
  92. int ret;
  93. u32 rbuffer;
  94. struct bcm2835_mbox_tag_hdr *tag;
  95. int tag_index;
  96. #ifdef DEBUG
  97. printf("mbox: TX buffer\n");
  98. dump_buf(buffer);
  99. #endif
  100. ret = bcm2835_mbox_call_raw(chan, (u32)buffer, &rbuffer);
  101. if (ret)
  102. return ret;
  103. if (rbuffer != (u32)buffer) {
  104. printf("mbox: Response buffer mismatch\n");
  105. return -1;
  106. }
  107. #ifdef DEBUG
  108. printf("mbox: RX buffer\n");
  109. dump_buf(buffer);
  110. #endif
  111. /* Validate overall response status */
  112. if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
  113. printf("mbox: Header response code invalid\n");
  114. return -1;
  115. }
  116. /* Validate each tag's response status */
  117. tag = (void *)(buffer + 1);
  118. tag_index = 0;
  119. while (tag->tag) {
  120. if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
  121. printf("mbox: Tag %d missing val_len response bit\n",
  122. tag_index);
  123. return -1;
  124. }
  125. /*
  126. * Clear the reponse bit so clients can just look right at the
  127. * length field without extra processing
  128. */
  129. tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
  130. tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
  131. tag_index++;
  132. }
  133. return 0;
  134. }