diff options
Diffstat (limited to 'src/cim/cim_init.c')
-rw-r--r-- | src/cim/cim_init.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/src/cim/cim_init.c b/src/cim/cim_init.c new file mode 100644 index 0000000..71f20b6 --- /dev/null +++ b/src/cim/cim_init.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2006 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. + */ + + /* + * Cimarron initialization routines. These routines detect a Geode LX and + * read all hardware base addresses. + */ + +CIMARRON_STATIC unsigned long init_video_base = 0x80000900; + +/*--------------------------------------------------------------------------- + * init_detect_cpu + * + * This routine verifies that a Geode LX is present and returns the processor + * revision ID. For compatibility, this routine can also detect a Redcloud + * processor. + * bits[24:16] = minor version + * bits[15:8] = major version + * bits[7:0] = type (1 = Geode GX, 2 = Geode LX) + *---------------------------------------------------------------------------*/ + +int +init_detect_cpu(unsigned long *cpu_revision, + unsigned long *companion_revision) +{ + unsigned long bus, device, i; + unsigned long cpu_bus = 0, cpu_device = 0; + unsigned long address, data; + unsigned long num_bars, function; + int cpu_found, sb_found; + Q_WORD msr_value; + + /* SEARCH THROUGH PCI BUS */ + /* We search the PCI bus for the Geode LX or Geode GX northbridge. */ + /* We then verify that one of its functions is the graphics */ + /* controller and that all bars are filled in. */ + + cpu_found = sb_found = 0; + for (bus = 0; bus < 256; bus++) { + for (device = 0; device < 21; device++) { + address = 0x80000000 | (bus << 16) | (device << 11); + + data = init_read_pci(address); + + if (data == PCI_VENDOR_DEVICE_GEODEGX + || data == PCI_VENDOR_DEVICE_GEODELX) { + cpu_found = 1; + cpu_device = device; + cpu_bus = bus; + if (data == PCI_VENDOR_DEVICE_GEODEGX) + *cpu_revision = CIM_CPU_GEODEGX; + else + *cpu_revision = CIM_CPU_GEODELX; + } else if (data == PCI_VENDOR_5535 || data == PCI_VENDOR_5536) { + sb_found = 1; + if (data == PCI_VENDOR_5535) + *companion_revision = CIM_SB_5535; + else + *companion_revision = CIM_SB_5536; + } + + if (cpu_found && sb_found) + break; + } + if (device != 21) + break; + } + + if (bus == 256) { + *cpu_revision = 0; + return CIM_STATUS_CPUNOTFOUND; + } + + msr_init_table(); + + if (msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_REVID, + &msr_value) != CIM_STATUS_OK) { + *cpu_revision = 0; + return CIM_STATUS_CPUNOTFOUND; + } + + *cpu_revision |= ((msr_value.low & 0xF0) << 4) | + ((msr_value.low & 0x0F) << 16); + + if (msr_read64(MSR_DEVICE_5535_GLCP, GLCP_REVID, + &msr_value) != CIM_STATUS_OK) { + *cpu_revision = 0; + return CIM_STATUS_CPUNOTFOUND; + } + + *companion_revision |= ((msr_value.low & 0xF0) << 4) | + ((msr_value.low & 0x0F) << 16); + + /* SEARCH ALL FUNCTIONS FOR INTEGRATED GRAPHICS */ + + num_bars = 0; + for (function = 0; function < 7; function++) { + address = 0x80000000 | (cpu_bus << 16) | (cpu_device << 11) | + (function << 8); + data = init_read_pci(address); + + if (data == PCI_VENDOR_DEVICE_GEODEGX_VIDEO) { + num_bars = 4; + break; + } else if (data == PCI_VENDOR_DEVICE_GEODELX_VIDEO) { + num_bars = 5; + break; + } + } + + /* VERIFY THAT ALL BARS ARE PRESENT */ + + if (function == 7) + return CIM_STATUS_DISPLAYUNAVAILABLE; + + for (i = 0; i < num_bars; i++) { + data = init_read_pci(address + 0x10 + (i << 2)); + + if (data == 0 || data == 0xFFFFFFFF) + break; + } + + if (i != num_bars) + return CIM_STATUS_DISPLAYUNAVAILABLE; + + /* SAVE VIDEO BASE ADDRESS FOR FUTURE CALLS */ + + init_video_base = address; + + return CIM_STATUS_OK; +} + +/*--------------------------------------------------------------------------- + * init_read_pci + * + * This routine reads an unsigned long value from a PCI address. + *---------------------------------------------------------------------------*/ + +unsigned long +init_read_pci(unsigned long address) +{ + OUTD(0xCF8, address); + return IND(0xCFC); +} + +/*--------------------------------------------------------------------------- + * init_read_base_addresses + * + * This routine reads all base addresses for the peripherals from the PCI + * BARs. + *---------------------------------------------------------------------------*/ + +int +init_read_base_addresses(INIT_BASE_ADDRESSES * base_addresses) +{ + unsigned long value; + + /* READ ALL BASE ADDRESSES */ + + base_addresses->framebuffer_base = init_read_pci(init_video_base + 0x10); + base_addresses->gp_register_base = init_read_pci(init_video_base + 0x14); + base_addresses->vg_register_base = init_read_pci(init_video_base + 0x18); + base_addresses->df_register_base = init_read_pci(init_video_base + 0x1C); + base_addresses->vip_register_base = init_read_pci(init_video_base + 0x20); + + /* READ FRAME BUFFER SIZE */ + /* The frame buffer size is reported by a VSM in VSA II */ + /* Virtual Register Class = 0x02 */ + /* VG_MEM_SIZE (1MB units) = 0x00 */ + + OUTW(0xAC1C, 0xFC53); + OUTW(0xAC1C, 0x0200); + + value = (unsigned long)(INW(0xAC1E)) & 0xFE; + + base_addresses->framebuffer_size = value << 20; + + return CIM_STATUS_OK; +} + +/*--------------------------------------------------------------------------- + * init_read_cpu_frequency + * + * This routine returns the current CPU core frequency, in MHz. + *---------------------------------------------------------------------------*/ + +int +init_read_cpu_frequency(unsigned long *cpu_frequency) +{ + /* CPU SPEED IS REPORTED BY A VSM IN VSA II */ + /* Virtual Register Class = 0x12 (Sysinfo) */ + /* CPU Speed Register = 0x01 */ + + OUTW(0xAC1C, 0xFC53); + OUTW(0xAC1C, 0x1201); + + *cpu_frequency = (unsigned long)(INW(0xAC1E)); + + return CIM_STATUS_OK; +} |