mbox.c 3.4 KB

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