mbox.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2012 Stephen Warren
  4. */
  5. #include <common.h>
  6. #include <cpu_func.h>
  7. #include <asm/cache.h>
  8. #include <asm/io.h>
  9. #include <asm/arch/base.h>
  10. #include <asm/arch/mbox.h>
  11. #include <phys2bus.h>
  12. #define TIMEOUT 1000 /* ms */
  13. int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
  14. {
  15. struct bcm2835_mbox_regs *regs =
  16. (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
  17. ulong endtime = get_timer(0) + TIMEOUT;
  18. u32 val;
  19. debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
  20. if (send & BCM2835_CHAN_MASK) {
  21. printf("mbox: Illegal mbox data 0x%08x\n", send);
  22. return -1;
  23. }
  24. /* Drain any stale responses */
  25. for (;;) {
  26. val = readl(&regs->mail0_status);
  27. if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
  28. break;
  29. if (get_timer(0) >= endtime) {
  30. printf("mbox: Timeout draining stale responses\n");
  31. return -1;
  32. }
  33. val = readl(&regs->read);
  34. }
  35. /* Wait for space to send */
  36. for (;;) {
  37. val = readl(&regs->mail1_status);
  38. if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
  39. break;
  40. if (get_timer(0) >= endtime) {
  41. printf("mbox: Timeout waiting for send space\n");
  42. return -1;
  43. }
  44. }
  45. /* Send the request */
  46. val = BCM2835_MBOX_PACK(chan, send);
  47. debug("mbox: TX raw: 0x%08x\n", val);
  48. writel(val, &regs->write);
  49. /* Wait for the response */
  50. for (;;) {
  51. val = readl(&regs->mail0_status);
  52. if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
  53. break;
  54. if (get_timer(0) >= endtime) {
  55. printf("mbox: Timeout waiting for response\n");
  56. return -1;
  57. }
  58. }
  59. /* Read the response */
  60. val = readl(&regs->read);
  61. debug("mbox: RX raw: 0x%08x\n", val);
  62. /* Validate the response */
  63. if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
  64. printf("mbox: Response channel mismatch\n");
  65. return -1;
  66. }
  67. *recv = BCM2835_MBOX_UNPACK_DATA(val);
  68. return 0;
  69. }
  70. #ifdef DEBUG
  71. void dump_buf(struct bcm2835_mbox_hdr *buffer)
  72. {
  73. u32 *p;
  74. u32 words;
  75. int i;
  76. p = (u32 *)buffer;
  77. words = buffer->buf_size / 4;
  78. for (i = 0; i < words; i++)
  79. printf(" 0x%04x: 0x%08x\n", i * 4, p[i]);
  80. }
  81. #endif
  82. int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
  83. {
  84. int ret;
  85. u32 rbuffer;
  86. struct bcm2835_mbox_tag_hdr *tag;
  87. int tag_index;
  88. #ifdef DEBUG
  89. printf("mbox: TX buffer\n");
  90. dump_buf(buffer);
  91. #endif
  92. flush_dcache_range((unsigned long)buffer,
  93. (unsigned long)((void *)buffer +
  94. roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
  95. ret = bcm2835_mbox_call_raw(chan,
  96. phys_to_bus((unsigned long)buffer),
  97. &rbuffer);
  98. if (ret)
  99. return ret;
  100. invalidate_dcache_range((unsigned long)buffer,
  101. (unsigned long)((void *)buffer +
  102. roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
  103. if (rbuffer != phys_to_bus((unsigned long)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. }