mbox.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2012 Stephen Warren
  4. */
  5. #include <common.h>
  6. #include <asm/io.h>
  7. #include <asm/arch/mbox.h>
  8. #include <phys2bus.h>
  9. #define TIMEOUT 1000 /* ms */
  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. flush_dcache_range((unsigned long)buffer,
  90. (unsigned long)((void *)buffer +
  91. roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
  92. ret = bcm2835_mbox_call_raw(chan,
  93. phys_to_bus((unsigned long)buffer),
  94. &rbuffer);
  95. if (ret)
  96. return ret;
  97. invalidate_dcache_range((unsigned long)buffer,
  98. (unsigned long)((void *)buffer +
  99. roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
  100. if (rbuffer != phys_to_bus((unsigned long)buffer)) {
  101. printf("mbox: Response buffer mismatch\n");
  102. return -1;
  103. }
  104. #ifdef DEBUG
  105. printf("mbox: RX buffer\n");
  106. dump_buf(buffer);
  107. #endif
  108. /* Validate overall response status */
  109. if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
  110. printf("mbox: Header response code invalid\n");
  111. return -1;
  112. }
  113. /* Validate each tag's response status */
  114. tag = (void *)(buffer + 1);
  115. tag_index = 0;
  116. while (tag->tag) {
  117. if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
  118. printf("mbox: Tag %d missing val_len response bit\n",
  119. tag_index);
  120. return -1;
  121. }
  122. /*
  123. * Clear the reponse bit so clients can just look right at the
  124. * length field without extra processing
  125. */
  126. tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
  127. tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
  128. tag_index++;
  129. }
  130. return 0;
  131. }