1 /*
2 * Copyright 2005-2009, 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 "framebuffer_private.h"
9 #include "vesa.h"
10
11 #include <string.h>
12
13 #include <drivers/bios.h>
14
15 #include <boot_item.h>
16 #include <frame_buffer_console.h>
17 #include <util/kernel_cpp.h>
18 #include <vm/vm.h>
19
20 #include "driver.h"
21 #include "utility.h"
22 #include "vesa_info.h"
23
24
25 static status_t
find_graphics_card(addr_t frameBuffer,addr_t & base,size_t & size)26 find_graphics_card(addr_t frameBuffer, addr_t& base, size_t& size)
27 {
28 // TODO: when we port this over to the new driver API, this mechanism can be
29 // used to find the right device_node
30 pci_module_info* pci;
31 if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) != B_OK)
32 return B_ERROR;
33
34 pci_info info;
35 for (int32 index = 0; pci->get_nth_pci_info(index, &info) == B_OK; index++) {
36 if (info.class_base != PCI_display)
37 continue;
38
39 // check PCI BARs
40 for (uint32 i = 0; i < 6; i++) {
41 phys_addr_t addr = info.u.h0.base_registers[i];
42 uint64 barSize = info.u.h0.base_register_sizes[i];
43 if (i < 5
44 && (info.u.h0.base_register_flags[i] & PCI_address_type) == PCI_address_type_64) {
45 addr |= (uint64)info.u.h0.base_registers[i + 1] << 32;
46 barSize |= (uint64)info.u.h0.base_register_sizes[i + 1] << 32;
47 i++;
48 }
49 if (addr <= frameBuffer && addr + barSize > frameBuffer) {
50 // found it!
51 base = addr;
52 size = barSize;
53 dprintf(DEVICE_NAME " find_graphics_card: found base 0x%lx size %" B_PRIuSIZE "\n",
54 base, size);
55
56 put_module(B_PCI_MODULE_NAME);
57 return B_OK;
58 }
59 }
60 }
61
62 dprintf(DEVICE_NAME " find_graphics_card: no entry found for 0x%lx\n", frameBuffer);
63 put_module(B_PCI_MODULE_NAME);
64 return B_ENTRY_NOT_FOUND;
65 }
66
67
68 static uint32
get_color_space_for_depth(uint32 depth)69 get_color_space_for_depth(uint32 depth)
70 {
71 switch (depth) {
72 case 1:
73 return B_GRAY1;
74 case 4:
75 return B_GRAY8;
76 // the app_server is smart enough to translate this to VGA mode
77 case 8:
78 return B_CMAP8;
79 case 15:
80 return B_RGB15;
81 case 16:
82 return B_RGB16;
83 case 24:
84 return B_RGB24;
85 case 32:
86 return B_RGB32;
87 }
88
89 return 0;
90 }
91
92
93 /*! Remaps the frame buffer if necessary; if we've already mapped the complete
94 frame buffer, there is no need to map it again.
95 */
96 static status_t
remap_frame_buffer(framebuffer_info & info,addr_t physicalBase,uint32 width,uint32 height,int8 depth,uint32 bytesPerRow,bool initializing)97 remap_frame_buffer(framebuffer_info& info, addr_t physicalBase, uint32 width,
98 uint32 height, int8 depth, uint32 bytesPerRow, bool initializing)
99 {
100 vesa_shared_info& sharedInfo = *info.shared_info;
101 addr_t frameBuffer = info.frame_buffer;
102
103 if (!info.complete_frame_buffer_mapped) {
104 addr_t base = physicalBase;
105 size_t size = bytesPerRow * height;
106 // TODO: this logic looks suspicious and may need refactoring
107 bool remap = !initializing || frameBuffer == 0;
108
109 if (info.physical_frame_buffer_size != 0) {
110 // we can map the complete frame buffer
111 base = info.physical_frame_buffer;
112 size = info.physical_frame_buffer_size;
113 remap = true;
114 }
115
116 if (remap) {
117 area_id area = map_physical_memory("framebuffer buffer", base,
118 size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA,
119 (void**)&frameBuffer);
120 if (area < 0)
121 return area;
122
123 if (initializing) {
124 // We need to manually update the kernel's frame buffer address,
125 // since this frame buffer remapping has not been issued by the
126 // app_server (which would otherwise take care of this)
127 frame_buffer_update(frameBuffer, width, height, depth,
128 bytesPerRow);
129 }
130
131 delete_area(info.shared_info->frame_buffer_area);
132
133 info.frame_buffer = frameBuffer;
134 sharedInfo.frame_buffer_area = area;
135
136 // Turn on write combining for the area
137 vm_set_area_memory_type(area, base, B_WRITE_COMBINING_MEMORY);
138
139 if (info.physical_frame_buffer_size != 0)
140 info.complete_frame_buffer_mapped = true;
141 }
142 }
143
144 if (info.complete_frame_buffer_mapped)
145 frameBuffer += physicalBase - info.physical_frame_buffer;
146
147 // Update shared frame buffer information
148 sharedInfo.frame_buffer = (uint8*)frameBuffer;
149 sharedInfo.physical_frame_buffer = (uint8*)physicalBase;
150 sharedInfo.bytes_per_row = bytesPerRow;
151
152 return B_OK;
153 }
154
155
156 // #pragma mark -
157
158
159 status_t
framebuffer_init(framebuffer_info & info)160 framebuffer_init(framebuffer_info& info)
161 {
162 frame_buffer_boot_info* bufferInfo
163 = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL);
164 if (bufferInfo == NULL)
165 return B_ERROR;
166
167 info.complete_frame_buffer_mapped = false;
168
169 // Find out which PCI device we belong to, so that we know its frame buffer
170 // size
171 find_graphics_card(bufferInfo->physical_frame_buffer,
172 info.physical_frame_buffer, info.physical_frame_buffer_size);
173
174 size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7;
175
176 info.shared_area = create_area("framebuffer shared info",
177 (void**)&info.shared_info, B_ANY_KERNEL_ADDRESS,
178 ROUND_TO_PAGE_SIZE(sharedSize), B_FULL_LOCK,
179 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
180 if (info.shared_area < 0)
181 return info.shared_area;
182
183 vesa_shared_info& sharedInfo = *info.shared_info;
184
185 memset(&sharedInfo, 0, sizeof(vesa_shared_info));
186
187 sharedInfo.frame_buffer_area = bufferInfo->area;
188
189 remap_frame_buffer(info, bufferInfo->physical_frame_buffer,
190 bufferInfo->width, bufferInfo->height, bufferInfo->depth,
191 bufferInfo->bytes_per_row, true);
192 // Does not matter if this fails - the frame buffer was already mapped
193 // before.
194
195 sharedInfo.current_mode.virtual_width = bufferInfo->width;
196 sharedInfo.current_mode.virtual_height = bufferInfo->height;
197 sharedInfo.current_mode.space = get_color_space_for_depth(
198 bufferInfo->depth);
199
200 edid1_info* edidInfo = (edid1_info*)get_boot_item(VESA_EDID_BOOT_INFO,
201 NULL);
202 if (edidInfo != NULL) {
203 sharedInfo.has_edid = true;
204 memcpy(&sharedInfo.edid_info, edidInfo, sizeof(edid1_info));
205 }
206
207 dprintf(DEVICE_NAME ": framebuffer_init() completed successfully!\n");
208 return B_OK;
209 }
210
211
212 void
framebuffer_uninit(framebuffer_info & info)213 framebuffer_uninit(framebuffer_info& info)
214 {
215 dprintf(DEVICE_NAME": framebuffer_uninit()\n");
216
217 delete_area(info.shared_info->frame_buffer_area);
218 delete_area(info.shared_area);
219 }
220