|
|
1.1 ! root 1: // Geode GX2/LX VGA functions ! 2: // ! 3: // Copyright (C) 2009 Chris Kindt ! 4: // ! 5: // Written for Google Summer of Code 2009 for the coreboot project ! 6: // ! 7: // This file may be distributed under the terms of the GNU LGPLv3 license. ! 8: ! 9: #include "geodevga.h" // geodevga_init ! 10: #include "farptr.h" // SET_FARVAR ! 11: #include "biosvar.h" // GET_BDA ! 12: #include "vgabios.h" // VGAREG_* ! 13: #include "util.h" // memset ! 14: #include "stdvga.h" // stdvga_crtc_write ! 15: #include "pci.h" // pci_config_readl ! 16: #include "pci_regs.h" // PCI_BASE_ADDRESS_0 ! 17: ! 18: ! 19: /**************************************************************** ! 20: * MSR and High Mem access through VSA Virtual Register ! 21: ****************************************************************/ ! 22: ! 23: static union u64_u32_u geode_msrRead(u32 msrAddr) ! 24: { ! 25: union u64_u32_u val; ! 26: asm __volatile__ ( ! 27: "movw $0x0AC1C, %%dx \n" ! 28: "movl $0xFC530007, %%eax \n" ! 29: "outl %%eax, %%dx \n" ! 30: "addb $2, %%dl \n" ! 31: "inw %%dx, %%ax \n" ! 32: : "=a" (val.lo), "=d"(val.hi) ! 33: : "c"(msrAddr) ! 34: : "cc" ! 35: ); ! 36: return val; ! 37: } ! 38: ! 39: static void geode_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo) ! 40: { ! 41: asm __volatile__ ( ! 42: "push %%eax \n" ! 43: "movw $0x0AC1C, %%dx \n" ! 44: "movl $0xFC530007, %%eax \n" ! 45: "outl %%eax, %%dx \n" ! 46: "addb $2, %%dl \n" ! 47: "pop %%eax \n" ! 48: "outw %%ax, %%dx \n" ! 49: : ! 50: : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo) ! 51: : "%edx","cc" ! 52: ); ! 53: } ! 54: ! 55: static u32 geode_memRead(u32 addr) ! 56: { ! 57: u32 val; ! 58: asm __volatile__ ( ! 59: "movw $0x0AC1C, %%dx \n" ! 60: "movl $0xFC530001, %%eax \n" ! 61: "outl %%eax, %%dx \n" ! 62: "addb $2, %%dl \n" ! 63: "inw %%dx, %%ax \n" ! 64: : "=a" (val) ! 65: : "b"(addr) ! 66: : "cc" ! 67: ); ! 68: ! 69: return val; ! 70: } ! 71: ! 72: static void geode_memWrite(u32 addr, u32 and, u32 or ) ! 73: { ! 74: asm __volatile__ ( ! 75: "movw $0x0AC1C, %%dx \n" ! 76: "movl $0xFC530001, %%eax \n" ! 77: "outl %%eax, %%dx \n" ! 78: "addb $2, %%dl \n" ! 79: "outw %%ax, %%dx \n" ! 80: : ! 81: : "b"(addr), "S" (and), "D" (or) ! 82: : "%eax","cc" ! 83: ); ! 84: } ! 85: ! 86: static int legacyio_check(void) ! 87: { ! 88: int ret=0; ! 89: union u64_u32_u val; ! 90: ! 91: if (CONFIG_VGA_GEODEGX2) ! 92: val=geode_msrRead(GLIU0_P2D_BM_4); ! 93: else ! 94: val=geode_msrRead(MSR_GLIU0_BASE4); ! 95: if (val.lo != 0x0A0fffe0) ! 96: ret|=1; ! 97: ! 98: val=geode_msrRead(GLIU0_IOD_BM_0); ! 99: if (val.lo != 0x3c0ffff0) ! 100: ret|=2; ! 101: ! 102: val=geode_msrRead(GLIU0_IOD_BM_1); ! 103: if (val.lo != 0x3d0ffff0) ! 104: ret|=4; ! 105: ! 106: return ret; ! 107: } ! 108: ! 109: /**************************************************************** ! 110: * Extened CRTC Register functions ! 111: ****************************************************************/ ! 112: static void crtce_lock(void) ! 113: { ! 114: stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK ! 115: , CRTCE_LOCK); ! 116: } ! 117: ! 118: static void crtce_unlock(void) ! 119: { ! 120: stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK ! 121: , CRTCE_UNLOCK); ! 122: } ! 123: ! 124: static u8 crtce_read(u8 reg) ! 125: { ! 126: crtce_unlock(); ! 127: u8 val = stdvga_crtc_read(VGAREG_VGA_CRTC_ADDRESS, reg); ! 128: crtce_lock(); ! 129: return val; ! 130: } ! 131: ! 132: static void crtce_write(u8 reg, u8 val) ! 133: { ! 134: crtce_unlock(); ! 135: stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, reg, val); ! 136: crtce_lock(); ! 137: } ! 138: ! 139: /**************************************************************** ! 140: * Display Controller Functions ! 141: ****************************************************************/ ! 142: static u32 dc_read(u16 seg, u32 reg) ! 143: { ! 144: u32 val, *dest_far = (void*)reg; ! 145: val = GET_FARVAR(seg,*dest_far); ! 146: return val; ! 147: } ! 148: ! 149: static void dc_write(u16 seg, u32 reg, u32 val) ! 150: { ! 151: u32 *dest_far = (void*)reg; ! 152: SET_FARVAR(seg,*dest_far,val); ! 153: } ! 154: ! 155: static void dc_set(u16 seg, u32 reg, u32 and, u32 or) ! 156: { ! 157: u32 val = dc_read(seg,reg); ! 158: val &=and; ! 159: val |=or; ! 160: dc_write(seg,reg,val); ! 161: } ! 162: ! 163: static void dc_unlock(u16 seg) ! 164: { ! 165: dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK); ! 166: } ! 167: ! 168: static void dc_lock(u16 seg) ! 169: { ! 170: dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK); ! 171: } ! 172: ! 173: static u16 dc_map(u16 seg) ! 174: { ! 175: u8 reg; ! 176: ! 177: reg = crtce_read(EXTENDED_MODE_CONTROL); ! 178: reg &= 0xf9; ! 179: switch (seg) { ! 180: case SEG_GRAPH: ! 181: reg |= 0x02; ! 182: break; ! 183: case SEG_MTEXT: ! 184: reg |= 0x04; ! 185: break; ! 186: case SEG_CTEXT: ! 187: reg |= 0x06; ! 188: break; ! 189: default: ! 190: seg=0; ! 191: break; ! 192: } ! 193: ! 194: crtce_write(EXTENDED_MODE_CONTROL,reg); ! 195: return seg; ! 196: } ! 197: ! 198: static void dc_unmap(void) ! 199: { ! 200: dc_map(0); ! 201: } ! 202: ! 203: ! 204: /**************************************************************** ! 205: * Init Functions ! 206: ****************************************************************/ ! 207: ! 208: /* Set up the dc (display controller) portion of the geodelx ! 209: * The dc provides hardware support for VGA graphics ! 210: * for features not accessible from the VGA registers, ! 211: * the dc's pci bar can be mapped to a vga memory segment ! 212: */ ! 213: static int dc_setup(void) ! 214: { ! 215: u32 fb, dc_fb; ! 216: u16 seg; ! 217: ! 218: dprintf(2, "DC_SETUP\n"); ! 219: ! 220: seg = dc_map(SEG_GRAPH); ! 221: dc_unlock(seg); ! 222: ! 223: /* zero memory config */ ! 224: dc_write(seg,DC_FB_ST_OFFSET,0x0); ! 225: dc_write(seg,DC_CB_ST_OFFSET,0x0); ! 226: dc_write(seg,DC_CURS_ST_OFFSET,0x0); ! 227: ! 228: /* read fb-bar from pci, then point dc to the fb base */ ! 229: dc_fb = dc_read(seg,DC_GLIU0_MEM_OFFSET); ! 230: fb = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_0); ! 231: if (fb!=dc_fb) { ! 232: dc_write(seg,DC_GLIU0_MEM_OFFSET,fb); ! 233: } ! 234: ! 235: dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP); ! 236: dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE); ! 237: ! 238: dc_lock(seg); ! 239: dc_unmap(); ! 240: ! 241: return 0; ! 242: } ! 243: ! 244: /* Setup the vp (video processor) portion of the geodelx ! 245: * Under VGA modes the vp was handled by softvg from inside VSA2. ! 246: * Without a softvg module, access is only available through a pci bar. ! 247: * The High Mem Access virtual register is used to configure the ! 248: * pci mmio bar from 16bit friendly io space. ! 249: */ ! 250: int vp_setup(void) ! 251: { ! 252: u32 reg,vp; ! 253: ! 254: dprintf(2,"VP_SETUP\n"); ! 255: /* set output to crt and RGB/YUV */ ! 256: if (CONFIG_VGA_GEODEGX2) ! 257: geode_msrWrite(VP_MSR_CONFIG_GX2, ~0, ~0xf8, 0, 0); ! 258: else ! 259: geode_msrWrite(VP_MSR_CONFIG_LX, ~0, ~0xf8, 0, 0); ! 260: ! 261: /* get vp register base from pci */ ! 262: vp = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_3); ! 263: ! 264: /* Set mmio registers ! 265: * there may be some timing issues here, the reads seem ! 266: * to slow things down enough work reliably ! 267: */ ! 268: ! 269: reg = geode_memRead(vp+VP_MISC); ! 270: dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg); ! 271: geode_memWrite(vp+VP_MISC,0,VP_BYP_BOTH); ! 272: reg = geode_memRead(vp+VP_MISC); ! 273: dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg); ! 274: ! 275: reg = geode_memRead(vp+VP_DCFG); ! 276: dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg); ! 277: geode_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW); ! 278: reg = geode_memRead(vp+VP_DCFG); ! 279: dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg); ! 280: ! 281: return 0; ! 282: } ! 283: ! 284: static u8 geode_crtc_01[] VAR16 = { ! 285: 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f, ! 286: 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, ! 287: 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3, ! 288: 0xff }; ! 289: static u8 geode_crtc_03[] VAR16 = { ! 290: 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f, ! 291: 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, ! 292: 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3, ! 293: 0xff }; ! 294: static u8 geode_crtc_04[] VAR16 = { ! 295: 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f, ! 296: 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ! 297: 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2, ! 298: 0xff }; ! 299: static u8 geode_crtc_05[] VAR16 = { ! 300: 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f, ! 301: 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ! 302: 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2, ! 303: 0xff }; ! 304: static u8 geode_crtc_06[] VAR16 = { ! 305: 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f, ! 306: 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ! 307: 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2, ! 308: 0xff }; ! 309: static u8 geode_crtc_07[] VAR16 = { ! 310: 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f, ! 311: 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, ! 312: 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3, ! 313: 0xff }; ! 314: static u8 geode_crtc_0d[] VAR16 = { ! 315: 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f, ! 316: 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ! 317: 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3, ! 318: 0xff }; ! 319: static u8 geode_crtc_0e[] VAR16 = { ! 320: 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f, ! 321: 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ! 322: 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3, ! 323: 0xff }; ! 324: static u8 geode_crtc_0f[] VAR16 = { ! 325: 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f, ! 326: 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ! 327: 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3, ! 328: 0xff }; ! 329: static u8 geode_crtc_11[] VAR16 = { ! 330: 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e, ! 331: 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ! 332: 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, ! 333: 0xff }; ! 334: static u8 geode_crtc_13[] VAR16 = { ! 335: 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f, ! 336: 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ! 337: 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3, ! 338: 0xff }; ! 339: ! 340: int geodevga_init(void) ! 341: { ! 342: int ret = stdvga_init(); ! 343: if (ret) ! 344: return ret; ! 345: ! 346: dprintf(1,"GEODEVGA_INIT\n"); ! 347: ! 348: if ((ret=legacyio_check())) { ! 349: dprintf(1,"GEODEVGA_INIT legacyio_check=0x%x\n",ret); ! 350: } ! 351: ! 352: // Updated timings from geode datasheets, table 6-53 in particular ! 353: static u8 *new_crtc[] VAR16 = { ! 354: geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03, ! 355: geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07, ! 356: 0, 0, 0, 0, 0, ! 357: geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f, ! 358: geode_crtc_11, geode_crtc_11, geode_crtc_13 }; ! 359: int i; ! 360: for (i=0; i<ARRAY_SIZE(new_crtc); i++) { ! 361: u8 *crtc = GET_GLOBAL(new_crtc[i]); ! 362: if (crtc) ! 363: stdvga_override_crtc(i, crtc); ! 364: } ! 365: ! 366: if (GET_GLOBAL(VgaBDF) < 0) ! 367: // Device should be at 00:01.1 ! 368: SET_VGA(VgaBDF, pci_to_bdf(0, 1, 1)); ! 369: ret |= vp_setup(); ! 370: ret |= dc_setup(); ! 371: ! 372: return ret; ! 373: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.