2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
9 #include <platform_def.h>
11 #include <arch_helpers.h>
12 #include <common/debug.h>
17 /* This struct must be aligned to 16 bytes */
18 typedef struct __packed
__aligned(16) rpi3_mbox_request
{
19 uint32_t size
; /* Buffer size in bytes */
20 uint32_t code
; /* Request/response code */
22 } rpi3_mbox_request_t
;
24 #define RPI3_MBOX_BUFFER_SIZE U(256)
25 static uint8_t __aligned(16) rpi3_mbox_buffer
[RPI3_MBOX_BUFFER_SIZE
];
27 /* Constants to perform a request/check the status of a request. */
28 #define RPI3_MBOX_PROCESS_REQUEST U(0x00000000)
29 #define RPI3_MBOX_REQUEST_SUCCESSFUL U(0x80000000)
30 #define RPI3_MBOX_REQUEST_ERROR U(0x80000001)
32 /* Command constants */
33 #define RPI3_TAG_HARDWARE_GET_BOARD_REVISION U(0x00010002)
34 #define RPI3_TAG_END U(0x00000000)
36 #define RPI3_TAG_REQUEST U(0x00000000)
37 #define RPI3_TAG_IS_RESPONSE U(0x80000000) /* Set if response */
38 #define RPI3_TAG_RESPONSE_LENGTH_MASK U(0x7FFFFFFF)
40 #define RPI3_CHANNEL_ARM_TO_VC U(0x8)
41 #define RPI3_CHANNEL_MASK U(0xF)
43 #define RPI3_MAILBOX_MAX_RETRIES U(1000000)
45 /*******************************************************************************
46 * Helpers to send requests to the VideoCore using the mailboxes.
47 ******************************************************************************/
48 static void rpi3_vc_mailbox_request_send(void)
51 uintptr_t resp_addr
, addr
;
54 /* This is the location of the request buffer */
55 addr
= (uintptr_t) &rpi3_mbox_buffer
;
57 /* Make sure that the changes are seen by the VideoCore */
58 flush_dcache_range(addr
, RPI3_MBOX_BUFFER_SIZE
);
60 /* Wait until the outbound mailbox is empty */
64 st
= mmio_read_32(RPI3_MBOX_BASE
+ RPI3_MBOX1_STATUS_OFFSET
);
67 if (retries
== RPI3_MAILBOX_MAX_RETRIES
) {
68 ERROR("rpi3: mbox: Send request timeout\n");
72 } while ((st
& RPI3_MBOX_STATUS_EMPTY_MASK
) == 0U);
74 /* Send base address of this message to start request */
75 mmio_write_32(RPI3_MBOX_BASE
+ RPI3_MBOX1_WRITE_OFFSET
,
76 RPI3_CHANNEL_ARM_TO_VC
| (uint32_t) addr
);
78 /* Wait until the inbound mailbox isn't empty */
82 st
= mmio_read_32(RPI3_MBOX_BASE
+ RPI3_MBOX0_STATUS_OFFSET
);
85 if (retries
== RPI3_MAILBOX_MAX_RETRIES
) {
86 ERROR("rpi3: mbox: Receive response timeout\n");
90 } while ((st
& RPI3_MBOX_STATUS_EMPTY_MASK
) != 0U);
92 /* Get location and channel */
93 data
= mmio_read_32(RPI3_MBOX_BASE
+ RPI3_MBOX0_READ_OFFSET
);
95 if ((data
& RPI3_CHANNEL_MASK
) != RPI3_CHANNEL_ARM_TO_VC
) {
96 ERROR("rpi3: mbox: Wrong channel: 0x%08x\n", data
);
100 resp_addr
= (uintptr_t)(data
& ~RPI3_CHANNEL_MASK
);
101 if (addr
!= resp_addr
) {
102 ERROR("rpi3: mbox: Unexpected address: 0x%08x\n", data
);
106 /* Make sure that the data seen by the CPU is up to date */
107 inv_dcache_range(addr
, RPI3_MBOX_BUFFER_SIZE
);
110 /*******************************************************************************
111 * Request board revision. Returns the revision and 0 on success, -1 on error.
112 ******************************************************************************/
113 int rpi3_vc_hardware_get_board_revision(uint32_t *revision
)
115 uint32_t tag_request_size
= sizeof(uint32_t);
116 rpi3_mbox_request_t
*req
= (rpi3_mbox_request_t
*) rpi3_mbox_buffer
;
118 assert(revision
!= NULL
);
120 VERBOSE("rpi3: mbox: Sending request at %p\n", (void *)req
);
122 req
->size
= sizeof(rpi3_mbox_buffer
);
123 req
->code
= RPI3_MBOX_PROCESS_REQUEST
;
125 req
->tags
[0] = RPI3_TAG_HARDWARE_GET_BOARD_REVISION
;
126 req
->tags
[1] = tag_request_size
; /* Space available for the response */
127 req
->tags
[2] = RPI3_TAG_REQUEST
;
128 req
->tags
[3] = 0; /* Placeholder for the response */
130 req
->tags
[4] = RPI3_TAG_END
;
132 rpi3_vc_mailbox_request_send();
134 if (req
->code
!= RPI3_MBOX_REQUEST_SUCCESSFUL
) {
135 ERROR("rpi3: mbox: Code = 0x%08x\n", req
->code
);
139 if (req
->tags
[2] != (RPI3_TAG_IS_RESPONSE
| tag_request_size
)) {
140 ERROR("rpi3: mbox: get board revision failed (0x%08x)\n",
145 *revision
= req
->tags
[3];