1/*
2 * Copyright 2012-2015 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_framebuffer.h"
13
14#include <arch/arm/bcm283X.h>
15#include <arch/cpu.h>
16#include <boot/stage2.h>
17#include <boot/platform.h>
18#include <boot/menu.h>
19#include <boot/kernel_args.h>
20#include <boot/platform/generic/video.h>
21#include <util/list.h>
22#include <drivers/driver_settings.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "arch_mailbox.h"
29#include "arch_mmu.h"
30#include "fdt_support.h"
31
32
33//XXX
34extern "C" bool
35mmu_get_virtual_mapping(addr_t virtualAddress, phys_addr_t *_physicalAddress);
36
37extern "C" ArchMailbox*
38arch_get_mailbox_arm_bcm2835(addr_t base);
39
40
41extern void* gFDT;
42
43
44struct framebuffer_config {
45	uint32	width;
46	uint32	height;
47	uint32	virtual_width;
48	uint32	virtual_height;
49	uint32	bytes_per_row;			// from GPU
50	uint32	bits_per_pixel;
51	uint32	x_offset;
52	uint32	y_offset;
53	uint32	frame_buffer_address;	// from GPU
54	uint32	screen_size;			// from GPU
55	uint16	color_map[256];
56};
57
58
59static framebuffer_config sFramebufferConfig __attribute__((aligned(16)));
60
61
62class ArchFBArmBCM2835 : public ArchFramebuffer {
63public:
64							ArchFBArmBCM2835(addr_t base)
65								: ArchFramebuffer(base) {}
66							~ArchFBArmBCM2835() {}
67
68virtual	status_t			Init();
69virtual	status_t			Probe();
70virtual	status_t			SetDefaultMode();
71virtual	status_t			SetVideoMode(int width, int height, int depth);
72private:
73		ArchMailbox*		fMailbox;
74};
75
76
77extern "C" ArchFramebuffer*
78arch_get_fb_arm_bcm2835(addr_t base)
79{
80    return new ArchFBArmBCM2835(base);
81}
82
83
84status_t
85ArchFBArmBCM2835::Init()
86{
87	if (!gFDT) {
88		dprintf("ERROR: FDT access is unavailable!");
89		return B_ERROR;
90	}
91	phys_addr_t mboxBase = fdt_get_device_reg_byname(gFDT, "/axi/mbox");
92	if (!mboxBase) {
93		dprintf("ERROR: /axi/mbox is unavailable!");
94		return B_ERROR;
95	}
96	fMailbox = arch_get_mailbox_arm_bcm2835(mboxBase);
97
98	if (fMailbox == NULL) {
99		dprintf("ERROR: Broadcom mailbox is unavailable!");
100		return B_ERROR;
101	}
102
103	gKernelArgs.frame_buffer.enabled = true;
104	return B_OK;
105}
106
107
108status_t
109ArchFBArmBCM2835::Probe()
110{
111	return B_OK;
112}
113
114
115status_t
116ArchFBArmBCM2835::SetDefaultMode()
117{
118	status_t result;
119	do {
120		result = SetVideoMode(1920, 1080, 16);
121	} while (result != B_OK);
122
123	return B_OK;
124}
125
126
127status_t
128ArchFBArmBCM2835::SetVideoMode(int width, int height, int depth)
129{
130	//debug_assert(((uint32)&sFramebufferConfig & 0x0f) == 0);
131
132	sFramebufferConfig.width = width;
133	sFramebufferConfig.height = height;
134	sFramebufferConfig.virtual_width = sFramebufferConfig.width;
135	sFramebufferConfig.virtual_height = sFramebufferConfig.height;
136	sFramebufferConfig.bytes_per_row = 0; // from GPU
137	sFramebufferConfig.bits_per_pixel = depth;
138	sFramebufferConfig.x_offset = 0;
139	sFramebufferConfig.y_offset = 0;
140	sFramebufferConfig.frame_buffer_address = 0; // from GPU
141	sFramebufferConfig.screen_size = 0; // from GPU
142
143	if (depth < 16) {
144		const int colorMapEntries = sizeof(sFramebufferConfig.color_map)
145			/ sizeof(sFramebufferConfig.color_map[0]);
146		for (int i = 0; i < colorMapEntries; i++)
147			sFramebufferConfig.color_map[i] = 0x1111 * i;
148	}
149
150	status_t result = fMailbox->Write(ARM_MAILBOX_CHANNEL_FRAMEBUFFER,
151		(uint32)&sFramebufferConfig | BCM283X_VIDEO_CORE_L2_COHERENT);
152	if (result != B_OK)
153		return result;
154
155	uint32 value;
156	result = fMailbox->Read(ARM_MAILBOX_CHANNEL_FRAMEBUFFER, value);
157	if (result != B_OK)
158		return result;
159
160	if (value != 0) {
161		dprintf("failed to configure framebuffer: %" B_PRIx32 "\n", value);
162		return B_ERROR;
163	}
164
165	if (sFramebufferConfig.frame_buffer_address == 0) {
166		dprintf("didn't get the framebuffer address\n");
167		return B_ERROR;
168	}
169
170	//debug_assert(sFramebufferConfig.x_offset == 0
171	//	&& sFramebufferConfig.y_offset == 0
172	//	&& sFramebufferConfig.width == (uint32)width
173	//	&& sFramebufferConfig.height == (uint32)height
174	//	&& sFramebufferConfig.virtual_width == sFramebufferConfig.width
175	//	&& sFramebufferConfig.virtual_height == sFramebufferConfig.height
176	//	&& sFramebufferConfig.bits_per_pixel == (uint32)depth
177	//	&& sFramebufferConfig.bytes_per_row
178	//		>= sFramebufferConfig.bits_per_pixel / 8
179	//			* sFramebufferConfig.width
180	//	&& sFramebufferConfig.screen_size >= sFramebufferConfig.bytes_per_row
181	//		* sFramebufferConfig.height);
182
183	fPhysicalBase
184		= BCM283X_BUS_TO_PHYSICAL(sFramebufferConfig.frame_buffer_address);
185	fSize = sFramebufferConfig.screen_size;
186
187	fBase = (addr_t)mmu_map_physical_memory(fPhysicalBase, fSize, kDefaultPageFlags);
188
189	dprintf("video framebuffer: va: %p pa: %p\n", (void *)fBase,
190		(void *)fPhysicalBase);
191
192	fCurrentWidth = width;
193	fCurrentHeight = height;
194	fCurrentDepth = depth;
195	fCurrentBytesPerRow = sFramebufferConfig.bytes_per_row;
196
197	gKernelArgs.frame_buffer.physical_buffer.start = (addr_t)fPhysicalBase;
198
199	return B_OK;
200}
201
202