1/*
2 * Copyright 2005-2015, Axel D��rfler, axeld@pinc-software.de.
3 * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <stdlib.h>
9#include <string.h>
10
11#include <compute_display_timing.h>
12#include <create_display_modes.h>
13
14#include "accelerant_protos.h"
15#include "accelerant.h"
16
17
18#define TRACE_MODE
19#ifdef TRACE_MODE
20extern "C" void _sPrintf(const char* format, ...);
21#	define TRACE(x) _sPrintf x
22#else
23#	define TRACE(x) ;
24#endif
25
26
27bool
28operator==(const display_mode &lhs, const display_mode &rhs)
29{
30	return lhs.space == rhs.space
31		&& lhs.virtual_width == rhs.virtual_width
32		&& lhs.virtual_height == rhs.virtual_height
33		&& lhs.h_display_start == rhs.h_display_start
34		&& lhs.v_display_start == rhs.v_display_start;
35}
36
37
38/*!	Checks if the specified \a mode can be set using VESA. */
39static bool
40is_mode_supported(display_mode* mode)
41{
42	return (mode != NULL) && (*mode == gInfo->shared_info->current_mode);
43}
44
45
46/*!	Creates the initial mode list of the primary accelerant.
47	It's called from vesa_init_accelerant().
48*/
49status_t
50create_mode_list(void)
51{
52	const color_space colorspace[] = {
53		(color_space)gInfo->shared_info->current_mode.space
54	};
55
56	if (!gInfo->shared_info->has_edid) {
57		display_mode mode = gInfo->shared_info->current_mode;
58
59		compute_display_timing(mode.virtual_width, mode.virtual_height, 60, false,
60			&mode.timing);
61		fill_display_mode(mode.virtual_width, mode.virtual_height, &mode);
62
63		gInfo->mode_list_area = create_display_modes("virtio_gpu modes",
64			NULL, &mode, 1, colorspace, 1, is_mode_supported, &gInfo->mode_list,
65			&gInfo->shared_info->mode_count);
66	} else {
67		edid1_info edidInfo;
68		edid_decode(&edidInfo, &gInfo->shared_info->edid_raw);
69		gInfo->mode_list_area = create_display_modes("virtio_gpu modes",
70			&edidInfo, NULL, 0, colorspace, 1, NULL, &gInfo->mode_list,
71			&gInfo->shared_info->mode_count);
72	}
73	if (gInfo->mode_list_area < 0)
74		return gInfo->mode_list_area;
75
76	gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
77	return B_OK;
78}
79
80
81//	#pragma mark -
82
83
84uint32
85virtio_gpu_accelerant_mode_count(void)
86{
87	TRACE(("virtio_gpu_accelerant_mode_count() = %d\n",
88		gInfo->shared_info->mode_count));
89	return gInfo->shared_info->mode_count;
90}
91
92
93status_t
94virtio_gpu_get_mode_list(display_mode* modeList)
95{
96	TRACE(("virtio_gpu_get_mode_info()\n"));
97	memcpy(modeList, gInfo->mode_list,
98		gInfo->shared_info->mode_count * sizeof(display_mode));
99	return B_OK;
100}
101
102
103status_t
104virtio_gpu_get_preferred_mode(display_mode* _mode)
105{
106	TRACE(("virtio_gpu_get_preferred_mode()\n"));
107	*_mode = gInfo->shared_info->current_mode;
108
109	return B_OK;
110}
111
112
113status_t
114virtio_gpu_set_display_mode(display_mode* _mode)
115{
116	TRACE(("virtio_gpu_set_display_mode()\n"));
117	if (_mode != NULL && *_mode == gInfo->shared_info->current_mode)
118		return B_OK;
119
120	return ioctl(gInfo->device, VIRTIO_GPU_SET_DISPLAY_MODE,
121		_mode, sizeof(display_mode));
122}
123
124
125status_t
126virtio_gpu_get_display_mode(display_mode* _currentMode)
127{
128	TRACE(("virtio_gpu_get_display_mode()\n"));
129	*_currentMode = gInfo->shared_info->current_mode;
130	return B_OK;
131}
132
133
134status_t
135virtio_gpu_get_edid_info(void* info, size_t size, uint32* _version)
136{
137	TRACE(("virtio_gpu_get_edid_info()\n"));
138
139	if (!gInfo->shared_info->has_edid)
140		return B_ERROR;
141	if (size < sizeof(struct edid1_info))
142		return B_BUFFER_OVERFLOW;
143
144	edid_decode((edid1_info*)info, &gInfo->shared_info->edid_raw);
145	*_version = EDID_VERSION_1;
146	edid_dump((edid1_info*)info);
147	return B_OK;
148}
149
150
151status_t
152virtio_gpu_get_frame_buffer_config(frame_buffer_config* config)
153{
154	TRACE(("virtio_gpu_get_frame_buffer_config()\n"));
155
156	config->frame_buffer = gInfo->shared_info->frame_buffer;
157	TRACE(("virtio_gpu_get_frame_buffer_config() = %" B_PRIxADDR "\n",
158		config->frame_buffer));
159	//config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer;
160	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
161	TRACE(("virtio_gpu_get_frame_buffer_config() %p\n", config->frame_buffer));
162	return B_OK;
163}
164
165
166status_t
167virtio_gpu_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high)
168{
169	TRACE(("virtio_gpu_get_pixel_clock_limits()\n"));
170
171	// TODO: do some real stuff here (taken from radeon driver)
172	uint32 totalPixel = (uint32)mode->timing.h_total
173		* (uint32)mode->timing.v_total;
174	uint32 clockLimit = 2000000;
175
176	// lower limit of about 48Hz vertical refresh
177	*_low = totalPixel * 48L / 1000L;
178	if (*_low > clockLimit)
179		return B_ERROR;
180
181	*_high = clockLimit;
182	return B_OK;
183}
184
185