mbox.c 3.5 KB

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