diff options
Diffstat (limited to 'src/drivers/xgi/common/xgi_coreboot.c')
-rwxr-xr-x | src/drivers/xgi/common/xgi_coreboot.c | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/src/drivers/xgi/common/xgi_coreboot.c b/src/drivers/xgi/common/xgi_coreboot.c new file mode 100755 index 0000000000..84ed81abd1 --- /dev/null +++ b/src/drivers/xgi/common/xgi_coreboot.c @@ -0,0 +1,436 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering + * + * xgifb_probe taken from the Linux xgifb driver (v3.18.5) and adapted for coreboot + * xgifb_modeset cobbled together from other portions of the same driver + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <delay.h> +#include <stdlib.h> +#include <string.h> +#include <arch/io.h> +#include <vbe.h> + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> + +#include <pc80/vga.h> + +#include "xgi_coreboot.h" +#include "vstruct.h" + +#include "XGIfb.h" +#include "XGI_main.h" +#include "vb_init.h" +#include "vb_util.h" +#include "vb_setmode.h" + +#include "XGI_main.c" + +static int xgi_vbe_valid; +static struct lb_framebuffer xgi_fb; + +int xgifb_probe(struct pci_dev *pdev, struct xgifb_video_info *xgifb_info) +{ + u8 reg, reg1; + u8 CR48, CR38; + int ret; + struct xgi_hw_device_info *hw_info; + unsigned long video_size_max; + + hw_info = &xgifb_info->hw_info; + xgifb_info->chip_id = pdev->device; + pci_read_config_byte(pdev, + PCI_REVISION_ID, + &xgifb_info->revision_id); + hw_info->jChipRevision = xgifb_info->revision_id; + + xgifb_info->subsysvendor = pdev->subsystem_vendor; + xgifb_info->subsysdevice = pdev->subsystem_device; + + video_size_max = pci_resource_len(pdev, 0); + xgifb_info->video_base = pci_resource_start(pdev, 0); + xgifb_info->mmio_base = pci_resource_start(pdev, 1); + xgifb_info->mmio_size = pci_resource_len(pdev, 1); + xgifb_info->vga_base = pci_resource_start(pdev, 2) + 0x30; + dev_info(&pdev->dev, "Relocate IO address: %Lx [%08lx]\n", + (u64) pci_resource_start(pdev, 2), + xgifb_info->vga_base); + + if (XGIfb_crt2type != -1) { + xgifb_info->display2 = XGIfb_crt2type; + xgifb_info->display2_force = true; + } + + XGIRegInit(&xgifb_info->dev_info, xgifb_info->vga_base); + + xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD); + reg1 = xgifb_reg_get(XGISR, IND_SIS_PASSWORD); + + if (reg1 != 0xa1) { + dev_err(&pdev->dev, "I/O error\n"); + ret = -5; + goto error_disable; + } + + switch (xgifb_info->chip_id) { + case PCI_DEVICE_ID_XGI_20: + xgifb_reg_or(XGICR, Index_CR_GPIO_Reg3, GPIOG_EN); + CR48 = xgifb_reg_get(XGICR, Index_CR_GPIO_Reg1); + if (CR48&GPIOG_READ) + xgifb_info->chip = XG21; + else + xgifb_info->chip = XG20; + break; + case PCI_DEVICE_ID_XGI_40: + xgifb_info->chip = XG40; + break; + case PCI_DEVICE_ID_XGI_42: + xgifb_info->chip = XG42; + break; + case PCI_DEVICE_ID_XGI_27: + xgifb_info->chip = XG27; + break; + default: + ret = -19; + goto error_disable; + } + + dev_info(&pdev->dev, "chipid = %x\n", xgifb_info->chip); + hw_info->jChipType = xgifb_info->chip; + + if (XGIfb_get_dram_size(xgifb_info)) { + xgifb_info->video_size = min_t(unsigned long, video_size_max, + SZ_16M); + } else if (xgifb_info->video_size > video_size_max) { + xgifb_info->video_size = video_size_max; + } + + /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */ + xgifb_reg_or(XGISR, + IND_SIS_PCI_ADDRESS_SET, + (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE)); + /* Enable 2D accelerator engine */ + xgifb_reg_or(XGISR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D); + + hw_info->ulVideoMemorySize = xgifb_info->video_size; + + xgifb_info->video_vbase = hw_info->pjVideoMemoryAddress = (void*)(intptr_t)xgifb_info->video_base; + xgifb_info->mmio_vbase = (void*)(intptr_t)xgifb_info->mmio_base; + + dev_info(&pdev->dev, + "Framebuffer at 0x%Lx, mapped to 0x%p, size %dk\n", + (u64) xgifb_info->video_base, + xgifb_info->video_vbase, + xgifb_info->video_size / 1024); + + dev_info(&pdev->dev, + "MMIO at 0x%Lx, mapped to 0x%p, size %ldk\n", + (u64) xgifb_info->mmio_base, xgifb_info->mmio_vbase, + xgifb_info->mmio_size / 1024); + + pci_set_drvdata(pdev, xgifb_info); + if (!XGIInitNew(pdev)) + dev_err(&pdev->dev, "XGIInitNew() failed!\n"); + + xgifb_info->mtrr = -1; + + xgifb_info->hasVB = HASVB_NONE; + if ((xgifb_info->chip == XG20) || + (xgifb_info->chip == XG27)) { + xgifb_info->hasVB = HASVB_NONE; + } else if (xgifb_info->chip == XG21) { + CR38 = xgifb_reg_get(XGICR, 0x38); + if ((CR38 & 0xE0) == 0xC0) + xgifb_info->display2 = XGIFB_DISP_LCD; + else if ((CR38 & 0xE0) == 0x60) + xgifb_info->hasVB = HASVB_CHRONTEL; + else + xgifb_info->hasVB = HASVB_NONE; + } else { + XGIfb_get_VB_type(xgifb_info); + } + + hw_info->ujVBChipID = VB_CHIP_UNKNOWN; + + hw_info->ulExternalChip = 0; + + switch (xgifb_info->hasVB) { + case HASVB_301: + reg = xgifb_reg_get(XGIPART4, 0x01); + if (reg >= 0xE0) { + hw_info->ujVBChipID = VB_CHIP_302LV; + dev_info(&pdev->dev, + "XGI302LV bridge detected (revision 0x%02x)\n", + reg); + } else if (reg >= 0xD0) { + hw_info->ujVBChipID = VB_CHIP_301LV; + dev_info(&pdev->dev, + "XGI301LV bridge detected (revision 0x%02x)\n", + reg); + } else { + hw_info->ujVBChipID = VB_CHIP_301; + dev_info(&pdev->dev, "XGI301 bridge detected\n"); + } + break; + case HASVB_302: + reg = xgifb_reg_get(XGIPART4, 0x01); + if (reg >= 0xE0) { + hw_info->ujVBChipID = VB_CHIP_302LV; + dev_info(&pdev->dev, + "XGI302LV bridge detected (revision 0x%02x)\n", + reg); + } else if (reg >= 0xD0) { + hw_info->ujVBChipID = VB_CHIP_301LV; + dev_info(&pdev->dev, + "XGI302LV bridge detected (revision 0x%02x)\n", + reg); + } else if (reg >= 0xB0) { + reg1 = xgifb_reg_get(XGIPART4, 0x23); + + hw_info->ujVBChipID = VB_CHIP_302B; + + } else { + hw_info->ujVBChipID = VB_CHIP_302; + dev_info(&pdev->dev, "XGI302 bridge detected\n"); + } + break; + case HASVB_LVDS: + hw_info->ulExternalChip = 0x1; + dev_info(&pdev->dev, "LVDS transmitter detected\n"); + break; + case HASVB_TRUMPION: + hw_info->ulExternalChip = 0x2; + dev_info(&pdev->dev, "Trumpion Zurac LVDS scaler detected\n"); + break; + case HASVB_CHRONTEL: + hw_info->ulExternalChip = 0x4; + dev_info(&pdev->dev, "Chrontel TV encoder detected\n"); + break; + case HASVB_LVDS_CHRONTEL: + hw_info->ulExternalChip = 0x5; + dev_info(&pdev->dev, + "LVDS transmitter and Chrontel TV encoder detected\n"); + break; + default: + dev_info(&pdev->dev, "No or unknown bridge type detected\n"); + break; + } + + if (xgifb_info->hasVB != HASVB_NONE) + XGIfb_detect_VB(xgifb_info); + else if (xgifb_info->chip != XG21) + xgifb_info->display2 = XGIFB_DISP_NONE; + + if (xgifb_info->display2 == XGIFB_DISP_LCD) { + if (!enable_dstn) { + reg = xgifb_reg_get(XGICR, IND_XGI_LCD_PANEL); + reg &= 0x0f; + hw_info->ulCRT2LCDType = XGI310paneltype[reg]; + } + } + + xgifb_info->mode_idx = -1; + + /* FIXME coreboot does not provide sscanf, needed by XGIfb_search_mode */ + /* if (mode) + XGIfb_search_mode(xgifb_info, mode); + else */if (vesa != -1) + XGIfb_search_vesamode(xgifb_info, vesa); + + if (xgifb_info->mode_idx >= 0) + xgifb_info->mode_idx = + XGIfb_validate_mode(xgifb_info, xgifb_info->mode_idx); + + if (xgifb_info->mode_idx < 0) { + if (xgifb_info->display2 == XGIFB_DISP_LCD && + xgifb_info->chip == XG21) + xgifb_info->mode_idx = + XGIfb_GetXG21DefaultLVDSModeIdx(xgifb_info); + else + xgifb_info->mode_idx = DEFAULT_MODE; + } + + if (xgifb_info->mode_idx < 0) { + dev_err(&pdev->dev, "No supported video mode found\n"); + ret = -22; + goto error_1; + } + + /* set default refresh rate */ + xgifb_info->refresh_rate = refresh_rate; + if (xgifb_info->refresh_rate == 0) + xgifb_info->refresh_rate = 60; + if (XGIfb_search_refresh_rate(xgifb_info, + xgifb_info->refresh_rate) == 0) { + xgifb_info->rate_idx = 1; + xgifb_info->refresh_rate = 60; + } + + xgifb_info->video_bpp = XGIbios_mode[xgifb_info->mode_idx].bpp; + xgifb_info->video_vwidth = + xgifb_info->video_width = + XGIbios_mode[xgifb_info->mode_idx].xres; + xgifb_info->video_vheight = + xgifb_info->video_height = + XGIbios_mode[xgifb_info->mode_idx].yres; + xgifb_info->org_x = xgifb_info->org_y = 0; + xgifb_info->video_linelength = + xgifb_info->video_width * + (xgifb_info->video_bpp >> 3); + switch (xgifb_info->video_bpp) { + case 8: + xgifb_info->DstColor = 0x0000; + xgifb_info->XGI310_AccelDepth = 0x00000000; + xgifb_info->video_cmap_len = 256; + break; + case 16: + xgifb_info->DstColor = 0x8000; + xgifb_info->XGI310_AccelDepth = 0x00010000; + xgifb_info->video_cmap_len = 16; + break; + case 32: + xgifb_info->DstColor = 0xC000; + xgifb_info->XGI310_AccelDepth = 0x00020000; + xgifb_info->video_cmap_len = 16; + break; + default: + xgifb_info->video_cmap_len = 16; + pr_info("Unsupported depth %d\n", + xgifb_info->video_bpp); + break; + } + + pr_info("Default mode is %dx%dx%d (%dHz)\n", + xgifb_info->video_width, + xgifb_info->video_height, + xgifb_info->video_bpp, + xgifb_info->refresh_rate); + + return 0; + +error_1: +error_disable: + free(xgifb_info); + return ret; +} + +int xgifb_modeset(struct pci_dev *pdev, struct xgifb_video_info *xgifb_info) +{ + struct xgi_hw_device_info *hw_info; + + hw_info = &xgifb_info->hw_info; + +#if IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) + /* Set mode */ + XGIfb_pre_setmode(xgifb_info); + if (XGISetModeNew(xgifb_info, hw_info, + XGIbios_mode[xgifb_info->mode_idx].mode_no) + == 0) { + pr_err("Setting mode[0x%x] failed\n", + XGIbios_mode[xgifb_info->mode_idx].mode_no); + return -22; + } + xgifb_info->video_linelength = + xgifb_info->video_width * + (xgifb_info->video_bpp >> 3); + + xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD); + + xgifb_reg_set(XGICR, 0x13, (xgifb_info->video_linelength & 0x00ff)); + xgifb_reg_set(XGISR, + 0x0E, + (xgifb_info->video_linelength & 0xff00) >> 8); + + XGIfb_post_setmode(xgifb_info); + + pr_debug("Set new mode: %dx%dx%d-%d\n", + XGIbios_mode[xgifb_info->mode_idx].xres, + XGIbios_mode[xgifb_info->mode_idx].yres, + XGIbios_mode[xgifb_info->mode_idx].bpp, + xgifb_info->refresh_rate); + + /* Set LinuxBIOS framebuffer information */ + xgi_vbe_valid = 1; + xgi_fb.physical_address = xgifb_info->video_base; + xgi_fb.x_resolution = xgifb_info->video_width; + xgi_fb.y_resolution = xgifb_info->video_height; + xgi_fb.bytes_per_line = xgifb_info->video_width * xgifb_info->video_bpp; + xgi_fb.bits_per_pixel = xgifb_info->video_bpp; + + xgi_fb.reserved_mask_pos = 0; + xgi_fb.reserved_mask_size = 0; + switch(xgifb_info->video_bpp){ + case 32: + case 24: + /* packed into 4-byte words */ + xgi_fb.reserved_mask_pos = 24; + xgi_fb.reserved_mask_size = 8; + xgi_fb.red_mask_pos = 16; + xgi_fb.red_mask_size = 8; + xgi_fb.green_mask_pos = 8; + xgi_fb.green_mask_size = 8; + xgi_fb.blue_mask_pos = 0; + xgi_fb.blue_mask_size = 8; + break; + case 16: + /* packed into 2-byte words */ + xgi_fb.red_mask_pos = 11; + xgi_fb.red_mask_size = 5; + xgi_fb.green_mask_pos = 5; + xgi_fb.green_mask_size = 6; + xgi_fb.blue_mask_pos = 0; + xgi_fb.blue_mask_size = 5; + break; + default: + printk(BIOS_SPEW, "%s: unsupported BPP %d\n", __func__, + xgifb_info->video_bpp); + xgi_vbe_valid = 0; + } +#else + /* FIXME + * Text mode does not work + */ + vga_io_init(); + vga_textmode_init(); +#endif + + return 0; +} + +int vbe_mode_info_valid(void) +{ + return xgi_vbe_valid; +} + +void fill_lb_framebuffer(struct lb_framebuffer *framebuffer) +{ + *framebuffer = xgi_fb; +} + +struct xgifb_video_info *xgifb_video_info_ptr; + +struct xgifb_video_info *pci_get_drvdata(struct pci_dev *pdev) { + return xgifb_video_info_ptr; +} + +void pci_set_drvdata(struct pci_dev *pdev, struct xgifb_video_info *data) { + xgifb_video_info_ptr = data; +}
\ No newline at end of file |