1/*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz, mmlr@mlotz.ch
7 *		Fran��ois Revol, revol@free.fr
8 *		Alexander von Gluck IV, kallisti5@unixzen.com
9 */
10
11
12#include "arch_mailbox.h"
13
14#include <atomic>
15#include <arch/arm/bcm283X.h>
16
17#include "arch_cpu.h"
18
19
20class ArchMailboxArmBCM2835 final : public ArchMailbox {
21public:
22							ArchMailboxArmBCM2835(addr_t base)
23								:
24								ArchMailbox(base) {}
25							~ArchMailboxArmBCM2835() {}
26
27virtual status_t			Write(uint8 channel, uint32 value) override;
28virtual status_t			Read(uint8 channel, uint32& value) override;
29
30private:
31		auto&				GetRegister(unsigned reg);
32		void				RegisterWrite(addr_t reg, uint32 value);
33		uint32				RegisterRead(addr_t reg);
34};
35
36
37extern "C" ArchMailbox*
38arch_get_mailbox_arm_bcm2835(addr_t base)
39{
40	return new ArchMailboxArmBCM2835(base);
41}
42
43
44status_t
45ArchMailboxArmBCM2835::Write(uint8 channel, uint32 value)
46{
47	// We have to wait for the mailbox to drain if it is marked full.
48	while ((RegisterRead(ARM_MAILBOX_STATUS) & ARM_MAILBOX_FULL) != 0)
49		;
50
51	value &= ARM_MAILBOX_DATA_MASK;
52	RegisterWrite(ARM_MAILBOX_WRITE, value | channel);
53	return B_OK;
54}
55
56
57status_t
58ArchMailboxArmBCM2835::Read(uint8 channel, uint32& value)
59{
60	while (true) {
61		// Wait for something to arrive in the mailbox.
62		if ((RegisterRead(ARM_MAILBOX_STATUS) & ARM_MAILBOX_EMPTY) != 0)
63			continue;
64
65		value = RegisterRead(ARM_MAILBOX_READ);
66		if ((value & ARM_MAILBOX_CHANNEL_MASK) != channel) {
67			// Not for us, retry.
68			continue;
69		}
70
71		break;
72	}
73
74	value &= ARM_MAILBOX_DATA_MASK;
75	return B_OK;
76}
77
78
79inline auto&
80ArchMailboxArmBCM2835::GetRegister(unsigned reg)
81{
82	auto addr = fBase + reg;
83	return *reinterpret_cast<std::atomic<uint32_t>*>(addr);
84}
85
86
87inline uint32
88ArchMailboxArmBCM2835::RegisterRead(addr_t reg)
89{
90	return GetRegister(reg).load(std::memory_order_acquire);
91}
92
93
94inline void
95ArchMailboxArmBCM2835::RegisterWrite(addr_t reg, uint32 value)
96{
97	GetRegister(reg).store(value, std::memory_order_release);
98}
99