blob: 88b25a0cd46eb24f2b03cfc7b587a099f125807e [file] [log] [blame]
/*
* (C) Copyright 2009-2011
* Max Tretene, ACube Systems Srl. mtretene@acube-systems.com.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <pci.h>
#include <sm501.h>
#include <video_fb.h>
#include "../common/vesa.h"
DECLARE_GLOBAL_DATA_PTR;
#undef DEBUG
#ifdef DEBUG
#define PRINTF(fmt,args...) printf (fmt ,##args)
#else
#define PRINTF(fmt,args...)
#endif
extern int execute_bios(pci_dev_t gr_dev, void *);
u32 fb_base_phys = 0;
u32 mmio_base_phys = 0;
u32 io_base_phys = 0;
int onbus = -1;
struct FrameBufferInfo *fbi = NULL;
pci_dev_t pci_find_radeon(struct pci_controller *ppc460_hose)
{
struct pci_controller * hose;
u16 vendor;
u8 header_type;
pci_dev_t bdf;
int bus, found_multi = 0;
static struct pci_device_id id;
id.vendor = PCI_VENDOR_ID_ATI;
for (hose = ppc460_hose; hose; hose = hose->next)
{
for (bus = 0; bus <= hose->last_busno; bus++)
{
PRINTF("pci_find_radeon %d\n",bus);
for (bdf = PCI_BDF(bus,0,0);
bdf < PCI_BDF(bus+1,0,0);
bdf += PCI_BDF(0,0,1))
{
if (!PCI_FUNC(bdf)) {
pci_read_config_byte(bdf,
PCI_HEADER_TYPE,
&header_type);
found_multi = header_type & 0x80;
} else {
if (!found_multi)
continue;
}
pci_read_config_word(bdf,
PCI_VENDOR_ID,
&vendor);
if (vendor == id.vendor)
{
onbus = bus;
return bdf;
}
}
}
}
return (-1);
}
int init_radeon(struct pci_controller *hose)
{
int jj;
unsigned char agp_control;
unsigned short cmd, devcmd;
pci_dev_t dev = ~0;
pci_dev_t bridge = ~0;
puts("VGA: ");
dev = pci_find_radeon(hose);
if (dev != -1)
{
PRINTF("RADEON found on %02x:%02x:%02x\n",
PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
// ----------------------------------------------------------
PRINTF("Shutting down graphics card at %x.%x.%x\n",
PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
// Graphics card...
pci_read_config_word(dev, PCI_COMMAND, &cmd);
devcmd = cmd;
cmd &= ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
pci_write_config_word(dev, PCI_COMMAND, cmd);
PRINTF(" CMD register now %X\n", cmd);
// ----------------------------------------------------------
//bridge = pci_find_bridge_for_bus(hose, PCI_BUS(dev));
bridge = PCI_BDF(0,0,0);
PRINTF("Behind bridge (%d) at %02x:%02x:%02x\n", bridge,
PCI_BUS(bridge), PCI_DEV(bridge), PCI_FUNC(bridge));
pci_read_config_byte(bridge, 0x3E, &agp_control);
agp_control |= 0x18;
pci_write_config_byte(bridge, 0x3E, agp_control);
// ----------------------------------------------------------
PRINTF("Re-enabling %x.%x.%x\n",
PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
pci_write_config_word(dev,
PCI_COMMAND, devcmd | PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
// ----------------------------------------------------------
#ifdef DEBUG2
PRINTF("\nCard Summary\n------------\n");
{
int bar, found_mem64;
unsigned int bar_response;
unsigned int io, mem;
pci_addr_t bar_value;
pci_size_t bar_size;
for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_5; bar += 4) {
pci_write_config_dword (dev, bar, 0xffffffff);
pci_read_config_dword (dev, bar, &bar_response);
if (!bar_response)
continue;
found_mem64 = 0;
io = 0;
mem = 0;
/* Check the BAR type and set our address mask */
if (bar_response & PCI_BASE_ADDRESS_SPACE) {
bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1;
/* round up region base address to a multiple of size */
io = 1; //((io - 1) | (bar_size - 1)) + 1;
//bar_value = io;
/* compute new region base address */
//io = io + bar_size;
} else {
if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
PCI_BASE_ADDRESS_MEM_TYPE_64) {
u32 bar_response_upper;
u64 bar64;
pci_write_config_dword(dev, bar+4, 0xffffffff);
pci_read_config_dword(dev, bar+4, &bar_response_upper);
bar64 = ((u64)bar_response_upper << 32) | bar_response;
bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
found_mem64 = 1;
} else {
bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
}
/* round up region base address to multiple of size */
mem = 1; //((mem - 1) | (bar_size - 1)) + 1;
//bar_value = mem;
/* compute new region base address */
//mem = mem + bar_size;
}
u32 low, high;
low = bar_size & 0xffffffff;
if (found_mem64) high = (bar_size >> 32) & 0xffffffff;
else high = 0;
PRINTF("bar_size = %08x%08x, io = %x, mem = %x mem64 = %x\n", high, low, io, mem, found_mem64);
if (found_mem64) bar += 4;
}
}
#endif
pci_read_config_dword(dev, PCI_BASE_ADDRESS_2, &mmio_base_phys);
mmio_base_phys &= ~0x0F;
PRINTF("mmio_base_phys = %08x\n",mmio_base_phys);
/* here we assume that a Radeon is on bus 0 (PCI) */
/* and a RadeonHD is on bus 1 or higher (PCI or PCI-E) */
if (onbus == 0)
pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &io_base_phys);
else
pci_read_config_dword(dev, PCI_BASE_ADDRESS_4, &io_base_phys);
io_base_phys &= ~0x0F;
PRINTF("io_base = %08x\n",io_base_phys);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &fb_base_phys);
fb_base_phys &= ~0x0F;
PRINTF("fb_base = %08x\n",fb_base_phys);
PRINTF("executing bios onbus=%d\n",onbus);
if (execute_bios(dev, TEXT_BASE))
{
puts("1\n");
u32 *tmp = fb_base_phys;
jj = (640 * 480) / 4;
while (jj--)
*tmp++ = 0;
puts("VESA: ");
// 257 = 640 x 480 - 8 bit
// 259 = 800 x 600 - 8 bit
fbi = set_vesa_mode(257);
if (fbi)
{
puts("OK\n");
// fixme: there is a problem with some radeon cards
// the fbi structure isn't filled with the required
// information, here we fill it in such case
PRINTF("%08x %d %d %d %d\n",fbi->BaseAddress,
fbi->XSize,
fbi->YSize,
fbi->BitsPerPixel,
fbi->Modulo);
if (fbi->BaseAddress != fb_base_phys)
{
fbi->BaseAddress = fb_base_phys;
fbi->XSize = 640;
fbi->YSize = 480;
fbi->BitsPerPixel = 8;
fbi->Modulo = 640;
PRINTF("%08x %d %d %d %d\n",fbi->BaseAddress,
fbi->XSize,
fbi->YSize,
fbi->BitsPerPixel,
fbi->Modulo);
}
drv_video_init();
}
else
puts("ERROR\n");
return 1;
}
else puts("ERROR EXECUTING BIOS\n");
}
else puts("NO CARDS\n");
return 0;
}