summaryrefslogtreecommitdiff
path: root/src/amd_gx_vga.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/amd_gx_vga.c')
-rw-r--r--src/amd_gx_vga.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/src/amd_gx_vga.c b/src/amd_gx_vga.c
new file mode 100644
index 0000000..2cb4adb
--- /dev/null
+++ b/src/amd_gx_vga.c
@@ -0,0 +1,450 @@
+/* Copyright (c) 2003-2005 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * */
+
+/*
+ * This file contains routines to set modes using the VGA registers.
+ * Since this file is for the first generation graphics unit, it interfaces
+ * to SoftVGA registers. It works for both VSA1 and VSA2.
+ * */
+
+/* VGA STRUCTURE */
+
+#define GU2_STD_CRTC_REGS 25
+#define GU2_EXT_CRTC_REGS 15
+#define GU2_GDC_REGS 9
+#define GU2_SEQ_REGS 5
+
+#define GU2_VGA_FLAG_MISC_OUTPUT 0x1
+#define GU2_VGA_FLAG_STD_CRTC 0x2
+#define GU2_VGA_FLAG_EXT_CRTC 0x4
+#define GU2_VGA_FLAG_GDC 0x10
+#define GU2_VGA_FLAG_SEQ 0x20
+#define GU2_VGA_FLAG_PALETTE 0x40
+#define GU2_VGA_FLAG_ATTR 0x80
+
+static unsigned int GDCregs[10];
+static unsigned int SEQregs[10];
+static unsigned int palette[256];
+static unsigned int ATTRregs[32];
+static unsigned char *font_data = NULL;
+
+#define VGA_BLOCK 0x40000 /* 256 k */
+
+void gu2_vga_extcrtc(char offset, int reset);
+int gu2_get_vga_active(void);
+void gu2_vga_font_data(int flag);
+void gu2_set_vga(int reset);
+int gu2_vga_seq_blanking(void);
+int gu2_vga_attr_ctrl(int reset);
+void gu2_vga_to_gfx(void);
+void gu2_gfx_to_vga(int vga_mode);
+int gu2_vga_seq_reset(int reset);
+int gu2_vga_save(gfx_vga_struct * vga, int flags);
+void gu2_vga_clear_extended(void);
+int gu2_vga_restore(gfx_vga_struct * vga, int flags);
+
+int
+gu2_get_vga_active(void)
+{
+ int data = gfx_read_reg32(MDC_GENERAL_CFG);
+
+ if (data & MDC_GCFG_VGAE)
+ return 1;
+
+ return 0;
+}
+
+void
+gu2_vga_font_data(int flag)
+{
+ if (flag == 0) {
+ if (font_data == NULL) {
+ font_data = malloc(VGA_BLOCK);
+ }
+
+ DEBUGMSG(1, (0, X_NONE, "Saving VGA Data\n"));
+ memcpy(font_data, gfx_virt_fbptr, VGA_BLOCK);
+ } else if (font_data) {
+ DEBUGMSG(1, (0, X_NONE, "Restore VGA Data\n"));
+ memcpy(gfx_virt_fbptr, font_data, VGA_BLOCK);
+ free(font_data);
+ font_data = NULL;
+ }
+}
+
+void
+gu2_set_vga(int reset)
+{
+ int data = gfx_read_reg32(MDC_GENERAL_CFG);
+
+ if (reset)
+ data |= MDC_GCFG_VGAE;
+ else
+ data &= ~MDC_GCFG_VGAE;
+
+ gfx_write_reg32(MDC_GENERAL_CFG, data);
+}
+
+int
+gu2_vga_seq_blanking(void)
+{
+ int tmp;
+
+ gfx_outb(0x3C4, 1);
+ tmp = gfx_inb(0x3C5);
+ tmp |= 0x20;
+ tmp |= tmp << 8;
+ gfx_outw(0x3C4, tmp);
+
+ gfx_delay_milliseconds(1);
+ return (GFX_STATUS_OK);
+}
+
+int
+gu2_vga_attr_ctrl(int reset)
+{
+ int tmp;
+
+ tmp = gfx_inb(0x3DA);
+ gfx_outb(0x3C0, (unsigned char)(reset ? 0x00 : 0x20));
+ if (reset)
+ tmp = gfx_inb(0x3DA);
+
+ return (GFX_STATUS_OK);
+}
+
+void
+gu2_vga_to_gfx(void)
+{
+ gu2_vga_attr_ctrl(0);
+
+ gu2_vga_seq_blanking();
+ gfx_delay_milliseconds(2);
+
+ gu2_vga_extcrtc(0x3F, 1);
+}
+
+void
+gu2_gfx_to_vga(int vga_mode)
+{
+ int tmp;
+ char sequencer;
+
+ gu2_vga_extcrtc(0x40, vga_mode);
+
+ /* clear the display blanking bit */
+ gfx_outb(MDC_SEQUENCER_INDEX, MDC_SEQUENCER_CLK_MODE);
+ sequencer = gfx_inb(MDC_SEQUENCER_DATA);
+ sequencer &= ~MDC_CLK_MODE_SCREEN_OFF;
+ sequencer |= 1;
+ gfx_outb(MDC_SEQUENCER_DATA, sequencer);
+
+ gfx_delay_milliseconds(1);
+
+ /*restart the sequencer */
+ gfx_outw(0x3C4, 0x300);
+
+ /* turn on the attribute controler */
+ tmp = gfx_inb(0x3DA);
+ gfx_outb(0x3C0, 0x20);
+ tmp = gfx_inb(0x3DA);
+
+ gu2_vga_extcrtc(0x3F, 0);
+}
+
+/*---------------------------------------------------------------------------
+ * gfx_vga_seq_reset
+ *
+ * This routine enables or disables SoftVGA. It is used to make SoftVGA
+ * "be quiet" and not interfere with any of the direct hardware access from
+ * Durango. For VSA1, the sequencer is reset to stop text redraws. VSA2 may
+ * provide a better way to have SoftVGA sit in the background.
+ *---------------------------------------------------------------------------
+ */
+int
+gu2_vga_seq_reset(int reset)
+{
+ gfx_outb(0x3C4, 0);
+ gfx_outb(0x3C5, (unsigned char)(reset ? 0x00 : 0x03));
+ return (GFX_STATUS_OK);
+}
+
+/*---------------------------------------------------------------------------
+ * gfx_vga_save
+ *
+ * This routine saves the state of the VGA registers into the specified
+ * structure. Flags indicate what portions of the register state need to
+ * be saved.
+ *----------------------------------------------------------------------------
+ */
+int
+gu2_vga_save(gfx_vga_struct * vga, int flags)
+{
+ int i;
+ unsigned short crtcindex, crtcdata;
+
+ crtcindex = (gfx_inb(0x3CC) & 0x01) ? 0x3D4 : 0x3B4;
+ crtcdata = crtcindex + 1;
+
+ /* CHECK MISCELLANEOUS OUTPUT FLAG */
+
+ if (flags & GU2_VGA_FLAG_MISC_OUTPUT) {
+ /* SAVE MISCCELLANEOUS OUTPUT REGISTER */
+ vga->miscOutput = gfx_inb(0x3CC);
+ }
+
+ /* CHECK SEQ */
+
+ if (flags & GU2_VGA_FLAG_SEQ) {
+ /* SAVE STANDARD CRTC REGISTERS */
+ for (i = 1; i < GU2_SEQ_REGS; i++) {
+ gfx_outb(0x3C4, (unsigned char)i);
+ SEQregs[i] = gfx_inb(0x3C5);
+ }
+ }
+
+ /* CHECK STANDARD CRTC FLAG */
+
+ if (flags & GU2_VGA_FLAG_STD_CRTC) {
+ /* SAVE STANDARD CRTC REGISTERS */
+ for (i = 0; i < GU2_STD_CRTC_REGS; i++) {
+ gfx_outb(crtcindex, (unsigned char)i);
+ vga->stdCRTCregs[i] = gfx_inb(crtcdata);
+ }
+ }
+
+ /* CHECK GDC */
+
+ if (flags & GU2_VGA_FLAG_GDC) {
+ /* SAVE STANDARD CRTC REGISTERS */
+ for (i = 0; i < GU2_GDC_REGS; i++) {
+ gfx_outb(0x3CE, (unsigned char)i);
+ GDCregs[i] = gfx_inb(0x3CF);
+ }
+ }
+
+ /* CHECK EXTENDED CRTC FLAG */
+
+ if (flags & GU2_VGA_FLAG_EXT_CRTC) {
+ /* SAVE EXTENDED CRTC REGISTERS */
+ for (i = 0; i < GU2_EXT_CRTC_REGS; i++) {
+ gfx_outb(crtcindex, (unsigned char)(0x40 + i));
+ vga->extCRTCregs[i] = gfx_inb(crtcdata);
+ }
+ }
+
+ if (flags & GU2_VGA_FLAG_PALETTE) {
+ /* SAVE PALETTE DATA */
+ for (i = 0; i < 0x100; i++) {
+ gfx_outb(0x3C7, i);
+ palette[i] = gfx_inb(0x3C9);
+ }
+ }
+
+ if (flags & GU2_VGA_FLAG_ATTR) {
+ /* SAVE Attribute DATA */
+ for (i = 0; i < 21; i++) {
+ gfx_inb(0x3DA);
+ gfx_outb(0x3C0, i);
+ ATTRregs[i] = gfx_inb(0x3C1);
+ }
+ }
+
+ /* save the VGA data */
+ gu2_vga_font_data(0);
+ return (0);
+}
+
+/*----------------------------------------------------------------------------
+ * gfx_vga_clear_extended
+ *
+ * This routine clears the extended SoftVGA register values to have SoftVGA
+ * behave like standard VGA.
+ *----------------------------------------------------------------------------
+ */
+void
+gu2_vga_clear_extended(void)
+{
+ int i;
+ unsigned short crtcindex, crtcdata;
+
+ crtcindex = (gfx_inb(0x3CC) & 0x01) ? 0x3D4 : 0x3B4;
+ crtcdata = crtcindex + 1;
+
+ gfx_outb(crtcindex, 0x30);
+ gfx_outb(crtcdata, 0x57);
+ gfx_outb(crtcdata, 0x4C);
+ for (i = 0x41; i <= 0x4F; i++) {
+ gfx_outb(crtcindex, (unsigned char)i);
+ gfx_outb(crtcdata, 0);
+ }
+
+ gfx_outb(crtcindex, 0x30);
+ gfx_outb(crtcdata, 0x00);
+}
+
+void
+gu2_vga_extcrtc(char offset, int reset)
+{
+ unsigned short crtcindex, crtcdata;
+
+ crtcindex = (gfx_inb(0x3CC) & 0x01) ? 0x3D4 : 0x3B4;
+ crtcdata = crtcindex + 1;
+
+ /* UNLOCK EXTENDED CRTC REGISTERS */
+
+ gfx_outb(crtcindex, 0x30);
+ gfx_outb(crtcdata, 0x57);
+ gfx_outb(crtcdata, 0x4C);
+
+ /* RESTORE EXTENDED CRTC REGISTERS */
+
+ gfx_outb(crtcindex, offset);
+ gfx_outb(crtcdata, reset);
+}
+
+/*----------------------------------------------------------------------------
+ * gfx_vga_restore
+ *
+ * This routine restores the state of the VGA registers from the specified
+ * structure. Flags indicate what portions of the register state need to
+ * be saved.
+ *----------------------------------------------------------------------------
+ */
+int
+gu2_vga_restore(gfx_vga_struct * vga, int flags)
+{
+ int i;
+ unsigned short crtcindex, crtcdata;
+
+ crtcindex = (gfx_inb(0x3CC) & 0x01) ? 0x3D4 : 0x3B4;
+ crtcdata = crtcindex + 1;
+
+ /* CHECK MISCELLANEOUS OUTPUT FLAG */
+
+ if (flags & GU2_VGA_FLAG_MISC_OUTPUT) {
+ /* RESTORE MISCELLANEOUS OUTPUT REGISTER VALUE */
+ gfx_outb(0x3C2, vga->miscOutput);
+ }
+
+ /* CHECK SEQ */
+
+ if (flags & GU2_VGA_FLAG_SEQ) {
+ /* RESTORE STANDARD CRTC REGISTERS */
+ for (i = 1; i < GU2_SEQ_REGS; i++) {
+ gfx_outb(0x3C4, (unsigned char)i);
+ gfx_outb(0x3C5, SEQregs[i]);
+ }
+ }
+
+ /* CHECK STANDARD CRTC FLAG */
+
+ if (flags & GU2_VGA_FLAG_STD_CRTC) {
+ /* UNLOCK STANDARD CRTC REGISTERS */
+ gfx_outb(crtcindex, 0x11);
+ gfx_outb(crtcdata, 0);
+
+ /* RESTORE STANDARD CRTC REGISTERS */
+
+ for (i = 0; i < GU2_STD_CRTC_REGS; i++) {
+ gfx_outb(crtcindex, (unsigned char)i);
+ gfx_outb(crtcdata, vga->stdCRTCregs[i]);
+ }
+ }
+
+ /* CHECK GDC */
+
+ if (flags & GU2_VGA_FLAG_GDC) {
+ /* SAVE STANDARD CRTC REGISTERS */
+ for (i = 0; i < GU2_GDC_REGS; i++) {
+ gfx_outb(0x3CE, (unsigned char)i);
+ gfx_outb(0x3CF, GDCregs[i]);
+ }
+ }
+
+ /* CHECK EXTENDED CRTC FLAG */
+
+ if (flags & GU2_VGA_FLAG_EXT_CRTC) {
+ /* UNLOCK EXTENDED CRTC REGISTERS */
+ gfx_outb(crtcindex, 0x30);
+ gfx_outb(crtcdata, 0x57);
+ gfx_outb(crtcdata, 0x4C);
+
+ /* RESTORE EXTENDED CRTC REGISTERS */
+
+ for (i = 1; i < GU2_EXT_CRTC_REGS; i++) {
+ gfx_outb(crtcindex, (unsigned char)(0x40 + i));
+ gfx_outb(crtcdata, vga->extCRTCregs[i]);
+ }
+
+ /* LOCK EXTENDED CRTC REGISTERS */
+
+ gfx_outb(crtcindex, 0x30);
+ gfx_outb(crtcdata, 0x00);
+
+ /* CHECK IF DIRECT FRAME BUFFER MODE (VESA MODE) */
+
+ if (vga->extCRTCregs[0x03] & 1) {
+ /* SET BORDER COLOR TO BLACK */
+ /* This really should be another thing saved/restored, but */
+ /* Durango currently doesn't do the attr controller registers. */
+
+ gfx_inb(0x3BA); /* Reset flip-flop */
+ gfx_inb(0x3DA);
+ gfx_outb(0x3C0, 0x11);
+ gfx_outb(0x3C0, 0x00);
+ }
+ }
+
+ if (flags & GU2_VGA_FLAG_PALETTE) {
+ /* RESTORE PALETTE DATA */
+ for (i = 0; i < 0x100; i++) {
+ gfx_outb(0x3C8, i);
+ gfx_outb(0x3C9, palette[i]);
+ }
+ }
+
+ if (flags & GU2_VGA_FLAG_ATTR) {
+ /* RESTORE Attribute DATA */
+ for (i = 0; i < 21; i++) {
+ gfx_inb(0x3DA);
+ gfx_outb(0x3C0, i);
+ gfx_outb(0x3C0, ATTRregs[i]);
+ }
+ /* SAVE Attribute DATA */
+
+ for (i = 0; i < 21; i++) {
+ gfx_inb(0x3DA);
+ gfx_outb(0x3C0, i);
+ }
+ }
+
+ /* restore the VGA data */
+ gu2_vga_font_data(1);
+
+ return (0);
+}
+
+/* END OF FILE */