CloverBootloader/Trash/Resolutions.c

757 lines
17 KiB
C

/*
*
* Created by Evan Lojewski on 3/4/10.
* Copyright 2009. All rights reserved.
*
*/
/* Copied from 915 resolution created by steve tomljenovic
*
* This code is based on the techniques used in :
*
* - 855patch. Many thanks to Christian Zietz (czietz gmx net)
* for demonstrating how to shadow the VBIOS into system RAM
* and then modify it.
*
* - 1280patch by Andrew Tipton (andrewtipton null li).
*
* - 855resolution by Alain Poirier
*
* This source code is into the public domain.
*/
/*
* based on work of DieBuche http://www.insanelymac.com/forum/index.php?showtopic=211294
*
* UEFI Clover adaptation - Slice 2012
*
*/
#include "Platform.h"
#include "Resolutions.h"
//Slice - nonsense. Obsolete chipset list
//will get from our GetDevice()
chipset_type get_chipset(UInt32 id)
{
chipset_type type;
switch (id) {
case 0x35758086:
type = CT_830;
break;
case 0x25608086:
type = CT_845G;
break;
case 0x35808086:
type = CT_855GM;
break;
case 0x25708086:
type = CT_865G;
break;
case 0x25808086:
type = CT_915G;
break;
case 0x25908086:
type = CT_915GM;
break;
case 0x27708086:
type = CT_945G;
break;
case 0x27a08086:
type = CT_945GM;
break;
case 0x27ac8086:
type = CT_945GME;
break;
case 0x29708086:
type = CT_946GZ;
break;
case 0x27748086:
type = CT_955X;
break;
case 0x277c8086:
type = CT_975X;
break;
case 0x29a08086:
type = CT_G965;
break;
case 0x29908086:
type = CT_Q965;
break;
case 0x81008086:
type = CT_500;
break;
case 0x2e108086:
case 0X2e908086:
type = CT_B43;
break;
case 0x2e208086:
type = CT_P45;
break;
case 0x2e308086:
type = CT_G41;
break;
case 0x29c08086:
type = CT_G31;
break;
case 0x29208086:
type = CT_G45;
break;
case 0xA0108086: // mobile
case 0xA0008086: // desktop
type = CT_3150;
break;
case 0x2a008086:
type = CT_965GM;
break;
case 0x29e08086:
type = CT_X48;
break;
case 0x2a408086:
type = CT_GM45;
break;
default:
if((id & 0x0000FFFF) == 0x00008086) // Intel chipset
{
//printf("Unknown chipset 0x%llX, please email id to meklort@gmail.com", id);
//getc();
type = CT_UNKNOWN_INTEL;
//type = CT_UNKNOWN;
}
else
{
type = CT_UNKNOWN;
}
break;
}
return type;
}
//Slice
//int getMode(edid_mode *mode)
//details about largest LCD mode. Will prepare in BioasVideo
//here we want to get LCD screen resolution that is disabled by VideoBios
//getResolution(&x, &y, &bp); -> getMode
vbios_resolution_type1 * map_type1_resolution(vbios_map * map, UInt16 res)
{
vbios_resolution_type1 * ptr = ((vbios_resolution_type1*)(map->bios_ptr + res));
return ptr;
}
vbios_resolution_type2 * map_type2_resolution(vbios_map * map, UInt16 res)
{
vbios_resolution_type2 * ptr = ((vbios_resolution_type2*)(map->bios_ptr + res));
return ptr;
}
vbios_resolution_type3 * map_type3_resolution(vbios_map * map, UInt16 res)
{
vbios_resolution_type3 * ptr = ((vbios_resolution_type3*)(map->bios_ptr + res));
return ptr;
}
char detect_bios_type(vbios_map * map, char modeline, int entry_size)
{
UInt32 i;
UInt16 r1, r2;
r1 = r2 = 32000;
for (i=0; i < map->mode_table_size; i++)
{
if (map->mode_table[i].resolution <= r1)
{
r1 = map->mode_table[i].resolution;
}
else
{
if (map->mode_table[i].resolution <= r2)
{
r2 = map->mode_table[i].resolution;
}
}
/*printf("r1 = %d r2 = %d\n", r1, r2);*/
}
return (r2-r1-6) % entry_size == 0;
}
vbios_map * open_vbios(chipset_type forced_chipset)
{
UInt32 z;
vbios_map * map = malloc(sizeof(vbios_map));
for(z=0; z<sizeof(vbios_map); z++) ((char*)map)[z]=0;
/*
* Determine chipset
*/
if (forced_chipset == CT_UNKNOWN)
{
map->chipset_id = get_chipset_id();
map->chipset = get_chipset(map->chipset_id);
}
else if (forced_chipset != CT_UNKNOWN)
{
map->chipset = forced_chipset;
}
if (map->chipset == CT_UNKNOWN)
{
//verbose("Unknown chipset type.\n");
//verbose("915resolution only works with Intel 800/900 series graphic chipsets.\n");
//verbose("Chipset Id: %x\n", map->chipset_id);
close_vbios(map);
return 0;
}
/*
* Map the video bios to memory
*/
map->bios_ptr=(char*)VBIOS_START;
/*
* check if we have ATI Radeon
*/
map->ati_tables.base = map->bios_ptr;
map->ati_tables.AtomRomHeader = (ATOM_ROM_HEADER *) (map->bios_ptr + *(unsigned short *) (map->bios_ptr + OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER));
if (strcmp ((char *) map->ati_tables.AtomRomHeader->uaFirmWareSignature, "ATOM") == 0)
{
// ATI Radeon Card
map->bios = BT_ATI_1;
map->ati_tables.MasterDataTables = (unsigned short *) &((ATOM_MASTER_DATA_TABLE *) (map->bios_ptr + map->ati_tables.AtomRomHeader->usMasterDataTableOffset))->ListOfDataTables;
unsigned short std_vesa_offset = (unsigned short) ((ATOM_MASTER_LIST_OF_DATA_TABLES *)map->ati_tables.MasterDataTables)->StandardVESA_Timing;
ATOM_STANDARD_VESA_TIMING * std_vesa = (ATOM_STANDARD_VESA_TIMING *) (map->bios_ptr + std_vesa_offset);
map->ati_mode_table = (char *) &std_vesa->aModeTimings;
if (map->ati_mode_table == 0)
{
printf("Unable to locate the mode table.\n");
printf("Please run the program 'dump_bios' as root and\n");
printf("email the file 'vbios.dmp' to stomljen@yahoo.com.\n");
printf("Chipset: %d\n", map->chipset);
close_vbios(map);
return 0;
}
map->mode_table_size = std_vesa->sHeader.usStructureSize - sizeof(ATOM_COMMON_TABLE_HEADER);
if (!detect_ati_bios_type(map)) map->bios = BT_ATI_2;
}
else {
/*
* check if we have NVIDIA
*/
int i = 0;
while (i < 512) { // we don't need to look through the whole bios, just the first 512 bytes
if (( map->bios_ptr[i] == 'N')
&& (map->bios_ptr[i+1] == 'V')
&& (map->bios_ptr[i+2] == 'I')
&& (map->bios_ptr[i+3] == 'D'))
{
map->bios = BT_NVDA;
unsigned short nv_data_table_offset = 0;
unsigned short * nv_data_table;
NV_VESA_TABLE * std_vesa;
int i = 0;
while (i < 0x300)
{ //We don't need to look for the table in the whole bios, the 768 first bytes only
if (( map->bios_ptr[i] == 0x44)
&& (map->bios_ptr[i+1] == 0x01)
&& (map->bios_ptr[i+2] == 0x04)
&& (map->bios_ptr[i+3] == 0x00))
{
nv_data_table_offset = (unsigned short) (map->bios_ptr[i+4] | (map->bios_ptr[i+5] << 8));
break;
}
i++;
}
nv_data_table = (unsigned short *) (map->bios_ptr + (nv_data_table_offset + OFFSET_TO_VESA_TABLE_INDEX));
std_vesa = (NV_VESA_TABLE *) (map->bios_ptr + *nv_data_table);
map->nv_mode_table = (char *) std_vesa->sModelines;
if (map->nv_mode_table == 0)
{
printf("Unable to locate the mode table.\n");
printf("Please run the program 'dump_bios' as root and\n");
printf("email the file 'vbios.dmp' to stomljen@yahoo.com.\n");
printf("Chipset: %s\n", map->chipset);
close_vbios(map);
return 0;
}
map->mode_table_size = std_vesa->sHeader.usTable_Size;
break;
}
i++;
}
}
/*
* check if we have Intel
*/
/*if (map->chipset == CT_UNKNOWN && memmem(map->bios_ptr, VBIOS_SIZE, INTEL_SIGNATURE, strlen(INTEL_SIGNATURE))) {
printf( "Intel chipset detected. However, 915resolution was unable to determine the chipset type.\n");
printf("Chipset Id: %x\n", map->chipset_id);
printf("Please report this problem to stomljen@yahoo.com\n");
close_vbios(map);
return 0;
}*/
/*
* check for others
*/
/*
* Figure out where the mode table is
*/
if ((map->bios != BT_ATI_1) && (map->bios != BT_NVDA))
{
char* p = map->bios_ptr + 16;
char* limit = map->bios_ptr + VBIOS_SIZE - (3 * sizeof(vbios_mode));
while (p < limit && map->mode_table == 0)
{
vbios_mode * mode_ptr = (vbios_mode *) p;
if (((mode_ptr[0].mode & 0xf0) == 0x30) && ((mode_ptr[1].mode & 0xf0) == 0x30) &&
((mode_ptr[2].mode & 0xf0) == 0x30) && ((mode_ptr[3].mode & 0xf0) == 0x30))
{
map->mode_table = mode_ptr;
}
p++;
}
if (map->mode_table == 0)
{
close_vbios(map);
return 0;
}
}
/*
* Determine size of mode table
*/
if ((map->bios != BT_ATI_1) && (map->bios != BT_ATI_2) && (map->bios != BT_NVDA))
{
vbios_mode * mode_ptr = map->mode_table;
while (mode_ptr->mode != 0xff)
{
map->mode_table_size++;
mode_ptr++;
}
}
/*
* Figure out what type of bios we have
* order of detection is important
*/
if ((map->bios != BT_ATI_1) && (map->bios != BT_ATI_2) && (map->bios != BT_NVDA))
{
if (detect_bios_type(map, TRUE, sizeof(vbios_modeline_type3)))
{
map->bios = BT_3;
}
else if (detect_bios_type(map, TRUE, sizeof(vbios_modeline_type2)))
{
map->bios = BT_2;
}
else if (detect_bios_type(map, FALSE, sizeof(vbios_resolution_type1)))
{
map->bios = BT_1;
}
else {
return 0;
}
}
return map;
}
void close_vbios(vbios_map * map)
{
free(map);
}
void unlock_vbios(vbios_map * map)
{
map->unlocked = TRUE;
switch (map->chipset) {
case CT_UNKNOWN:
break;
case CT_830:
case CT_855GM:
outl(CONFIG_MECH_ONE_ADDR, 0x8000005a);
map->b1 = inb(CONFIG_MECH_ONE_DATA + 2);
outl(CONFIG_MECH_ONE_ADDR, 0x8000005a);
outb(CONFIG_MECH_ONE_DATA + 2, 0x33);
break;
case CT_845G:
case CT_865G:
case CT_915G:
case CT_915GM:
case CT_945G:
case CT_945GM:
case CT_945GME:
case CT_946GZ:
case CT_G965:
case CT_Q965:
case CT_965GM:
case CT_975X:
case CT_P35:
case CT_955X:
case CT_X48:
case CT_B43:
case CT_Q45:
case CT_P45:
case CT_GM45:
case CT_G45:
case CT_G41:
case CT_G31:
case CT_500:
case CT_3150:
case CT_UNKNOWN_INTEL: // Assume newer intel chipset is the same as before
outl(CONFIG_MECH_ONE_ADDR, 0x80000090);
map->b1 = inb(CONFIG_MECH_ONE_DATA + 1);
map->b2 = inb(CONFIG_MECH_ONE_DATA + 2);
outl(CONFIG_MECH_ONE_ADDR, 0x80000090);
outb(CONFIG_MECH_ONE_DATA + 1, 0x33);
outb(CONFIG_MECH_ONE_DATA + 2, 0x33);
break;
}
#if DEBUG
{
UInt32 t = inl(CONFIG_MECH_ONE_DATA);
verbose("unlock PAM: (0x%08x)\n", t);
}
#endif
}
void relock_vbios(vbios_map * map)
{
map->unlocked = FALSE;
switch (map->chipset)
{
case CT_UNKNOWN:
break;
case CT_830:
case CT_855GM:
outl(CONFIG_MECH_ONE_ADDR, 0x8000005a);
outb(CONFIG_MECH_ONE_DATA + 2, map->b1);
break;
case CT_845G:
case CT_865G:
case CT_915G:
case CT_915GM:
case CT_945G:
case CT_945GM:
case CT_945GME:
case CT_946GZ:
case CT_G965:
case CT_955X:
case CT_G45:
case CT_Q965:
case CT_965GM:
case CT_975X:
case CT_P35:
case CT_X48:
case CT_B43:
case CT_Q45:
case CT_P45:
case CT_GM45:
case CT_G41:
case CT_G31:
case CT_500:
case CT_3150:
case CT_UNKNOWN_INTEL:
outl(CONFIG_MECH_ONE_ADDR, 0x80000090);
outb(CONFIG_MECH_ONE_DATA + 1, map->b1);
outb(CONFIG_MECH_ONE_DATA + 2, map->b2);
break;
}
#if DEBUG
{
UInt32 t = inl(CONFIG_MECH_ONE_DATA);
verbose("relock PAM: (0x%08x)\n", t);
}
#endif
}
static void gtf_timings(UInt32 x, UInt32 y, UInt32 freq,
unsigned long *clock,
UInt16 *hsyncstart, UInt16 *hsyncend, UInt16 *hblank,
UInt16 *vsyncstart, UInt16 *vsyncend, UInt16 *vblank)
{
UInt32 hbl, vbl, vfreq;
vbl = y + (y+1)/(20000.0/(11*freq) - 1) + 1.5;
vfreq = vbl * freq;
hbl = 16 * (int)(x * (30.0 - 300000.0 / vfreq) /
+ (70.0 + 300000.0 / vfreq) / 16.0 + 0.5);
*vsyncstart = y;
*vsyncend = y + 3;
*vblank = vbl - 1;
*hsyncstart = x + hbl / 2 - (x + hbl + 50) / 100 * 8 - 1;
*hsyncend = x + hbl / 2 - 1;
*hblank = x + hbl - 1;
*clock = (x + hbl) * vfreq / 1000;
}
void set_mode(vbios_map * map, /*UInt32 mode,*/ UInt32 x, UInt32 y, UInt32 bp, UInt32 htotal, UInt32 vtotal) {
UInt32 xprev, yprev;
UInt32 i = 0, j;
// patch first available mode
// for (i=0; i < map->mode_table_size; i++) {
// if (map->mode_table[0].mode == mode) {
switch(map->bios) {
case BT_INTEL:
return;
case BT_1:
{
vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution);
if (bp) {
map->mode_table[i].bits_per_pixel = bp;
}
res->x2 = (htotal?(((htotal-x) >> 8) & 0x0f) : (res->x2 & 0x0f)) | ((x >> 4) & 0xf0);
res->x1 = (x & 0xff);
res->y2 = (vtotal?(((vtotal-y) >> 8) & 0x0f) : (res->y2 & 0x0f)) | ((y >> 4) & 0xf0);
res->y1 = (y & 0xff);
if (htotal)
res->x_total = ((htotal-x) & 0xff);
if (vtotal)
res->y_total = ((vtotal-y) & 0xff);
break;
}
case BT_2:
{
vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution);
res->xchars = x / 8;
res->ychars = y / 16 - 1;
xprev = res->modelines[0].x1;
yprev = res->modelines[0].y1;
for(j=0; j < 3; j++) {
vbios_modeline_type2 * modeline = &res->modelines[j];
if (modeline->x1 == xprev && modeline->y1 == yprev) {
modeline->x1 = modeline->x2 = x-1;
modeline->y1 = modeline->y2 = y-1;
gtf_timings(x, y, freqs[j], &modeline->clock,
&modeline->hsyncstart, &modeline->hsyncend,
&modeline->hblank, &modeline->vsyncstart,
&modeline->vsyncend, &modeline->vblank);
if (htotal)
modeline->htotal = htotal;
else
modeline->htotal = modeline->hblank;
if (vtotal)
modeline->vtotal = vtotal;
else
modeline->vtotal = modeline->vblank;
}
}
break;
}
case BT_3:
{
vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution);
xprev = res->modelines[0].x1;
yprev = res->modelines[0].y1;
for (j=0; j < 3; j++) {
vbios_modeline_type3 * modeline = &res->modelines[j];
if (modeline->x1 == xprev && modeline->y1 == yprev) {
modeline->x1 = modeline->x2 = x-1;
modeline->y1 = modeline->y2 = y-1;
gtf_timings(x, y, freqs[j], &modeline->clock,
&modeline->hsyncstart, &modeline->hsyncend,
&modeline->hblank, &modeline->vsyncstart,
&modeline->vsyncend, &modeline->vblank);
if (htotal)
modeline->htotal = htotal;
else
modeline->htotal = modeline->hblank;
if (vtotal)
modeline->vtotal = vtotal;
else
modeline->vtotal = modeline->vblank;
modeline->timing_h = y-1;
modeline->timing_v = x-1;
}
}
break;
}
case BT_ATI_1:
{
edid_mode mode;
ATOM_MODE_TIMING *mode_timing = (ATOM_MODE_TIMING *) map->ati_mode_table;
//if (mode.pixel_clock && (mode.h_active == x) && (mode.v_active == y) && !force) {
if (!getMode(&mode)) {
mode_timing->usCRTC_H_Total = mode.h_active + mode.h_blanking;
mode_timing->usCRTC_H_Disp = mode.h_active;
mode_timing->usCRTC_H_SyncStart = mode.h_active + mode.h_sync_offset;
mode_timing->usCRTC_H_SyncWidth = mode.h_sync_width;
mode_timing->usCRTC_V_Total = mode.v_active + mode.v_blanking;
mode_timing->usCRTC_V_Disp = mode.v_active;
mode_timing->usCRTC_V_SyncStart = mode.v_active + mode.v_sync_offset;
mode_timing->usCRTC_V_SyncWidth = mode.v_sync_width;
mode_timing->usPixelClock = mode.pixel_clock;
}
break;
}
case BT_ATI_2:
{
edid_mode mode;
ATOM_DTD_FORMAT *mode_timing = (ATOM_DTD_FORMAT *) map->ati_mode_table;
/*if (mode.pixel_clock && (mode.h_active == x) && (mode.v_active == y) && !force) {*/
if (!getMode(&mode)) {
mode_timing->usHBlanking_Time = mode.h_blanking;
mode_timing->usHActive = mode.h_active;
mode_timing->usHSyncOffset = mode.h_sync_offset;
mode_timing->usHSyncWidth = mode.h_sync_width;
mode_timing->usVBlanking_Time = mode.v_blanking;
mode_timing->usVActive = mode.v_active;
mode_timing->usVSyncOffset = mode.v_sync_offset;
mode_timing->usVSyncWidth = mode.v_sync_width;
mode_timing->usPixClk = mode.pixel_clock;
}
break;
}
case BT_NVDA:
{
edid_mode mode;
NV_MODELINE *mode_timing = (NV_MODELINE *) map->nv_mode_table;
/*if (mode.pixel_clock && (mode.h_active == x) && (mode.v_active == y) && !force) {*/
if (!getMode(&mode)) {
mode_timing[i].usH_Total = mode.h_active + mode.h_blanking;
mode_timing[i].usH_Active = mode.h_active;
mode_timing[i].usH_SyncStart = mode.h_active + mode.h_sync_offset;
mode_timing[i].usH_SyncEnd = mode.h_active + mode.h_sync_offset + mode.h_sync_width;
mode_timing[i].usV_Total = mode.v_active + mode.v_blanking;
mode_timing[i].usV_Active = mode.v_active;
mode_timing[i].usV_SyncStart = mode.v_active + mode.v_sync_offset;
mode_timing[i].usV_SyncEnd = mode.v_active + mode.v_sync_offset + mode.v_sync_width;
mode_timing[i].usPixel_Clock = mode.pixel_clock;
}
break;
}
case BT_UNKNOWN:
{
break;
}
}
}
VOID patchVideoBios()
{
UINT32 x = 0, y = 0, bp = 32;
vbios_map * map;
//here we want to get LCD screen resolution that is disabled by VideoBios
getResolution(&x, &y, &bp);
if (x != 0 &&
y != 0 &&
bp != 0)
{
map = open_vbios(CT_UNKNOWN);
if(map)
{
unlock_vbios(map);
set_mode(map, x, y, bp, 0, 0);
relock_vbios(map);
close_vbios(map);
}
}
}