summaryrefslogtreecommitdiff
path: root/src/drivers/xgi/common/xgi_coreboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/xgi/common/xgi_coreboot.c')
-rwxr-xr-xsrc/drivers/xgi/common/xgi_coreboot.c436
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