1f29dbc25Smrg/*
2f29dbc25Smrg * Copyright (c) 2006 Advanced Micro Devices, Inc.
3f29dbc25Smrg *
4f29dbc25Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5f29dbc25Smrg * copy of this software and associated documentation files (the "Software"),
6f29dbc25Smrg * to deal in the Software without restriction, including without limitation
7f29dbc25Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8f29dbc25Smrg * and/or sell copies of the Software, and to permit persons to whom the
9f29dbc25Smrg * Software is furnished to do so, subject to the following conditions:
10f29dbc25Smrg *
11f29dbc25Smrg * The above copyright notice and this permission notice shall be included in
12f29dbc25Smrg * all copies or substantial portions of the Software.
13f29dbc25Smrg *
14f29dbc25Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15f29dbc25Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16f29dbc25Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17f29dbc25Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18f29dbc25Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19f29dbc25Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20f29dbc25Smrg * DEALINGS IN THE SOFTWARE.
21f29dbc25Smrg *
22f29dbc25Smrg * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
23f29dbc25Smrg * contributors may be used to endorse or promote products derived from this
24f29dbc25Smrg * software without specific prior written permission.
25f29dbc25Smrg */
26f29dbc25Smrg
27f29dbc25Smrg /*
28f29dbc25Smrg  * Cimarron initialization routines.  These routines detect a Geode LX and
29f29dbc25Smrg  * read all hardware base addresses.
30f29dbc25Smrg  */
31f29dbc25Smrg
32f29dbc25SmrgCIMARRON_STATIC unsigned long init_video_base = 0x80000900;
33f29dbc25Smrg
34f29dbc25Smrg/*---------------------------------------------------------------------------
35f29dbc25Smrg * init_detect_cpu
36f29dbc25Smrg *
37f29dbc25Smrg * This routine verifies that a Geode LX is present and returns the processor
38f29dbc25Smrg * revision ID.  For compatibility, this routine can also detect a Redcloud
39f29dbc25Smrg * processor.
40f29dbc25Smrg *     bits[24:16] = minor version
41f29dbc25Smrg *     bits[15:8]  = major version
42f29dbc25Smrg *     bits[7:0]   = type (1 = Geode GX, 2 = Geode LX)
43f29dbc25Smrg *---------------------------------------------------------------------------*/
44f29dbc25Smrg
45f29dbc25Smrgint
4604007ebaSmrginit_detect_cpu(unsigned long *cpu_revision, unsigned long *companion_revision)
47f29dbc25Smrg{
48f29dbc25Smrg    unsigned long bus, device, i;
49f29dbc25Smrg    unsigned long cpu_bus = 0, cpu_device = 0;
50f29dbc25Smrg    unsigned long address, data;
51f29dbc25Smrg    unsigned long num_bars, function;
52f29dbc25Smrg    int cpu_found, sb_found;
53f29dbc25Smrg    Q_WORD msr_value;
54f29dbc25Smrg
55f29dbc25Smrg    /* SEARCH THROUGH PCI BUS                                          */
56f29dbc25Smrg    /* We search the PCI bus for the Geode LX or Geode GX northbridge. */
57f29dbc25Smrg    /* We then verify that one of its functions is the graphics        */
58f29dbc25Smrg    /* controller and that all bars are filled in.                     */
59f29dbc25Smrg
60f29dbc25Smrg    cpu_found = sb_found = 0;
61f29dbc25Smrg    for (bus = 0; bus < 256; bus++) {
62f29dbc25Smrg        for (device = 0; device < 21; device++) {
63f29dbc25Smrg            address = 0x80000000 | (bus << 16) | (device << 11);
64f29dbc25Smrg
65f29dbc25Smrg            data = init_read_pci(address);
66f29dbc25Smrg
67f29dbc25Smrg            if (data == PCI_VENDOR_DEVICE_GEODEGX
68f29dbc25Smrg                || data == PCI_VENDOR_DEVICE_GEODELX) {
69f29dbc25Smrg                cpu_found = 1;
70f29dbc25Smrg                cpu_device = device;
71f29dbc25Smrg                cpu_bus = bus;
72f29dbc25Smrg                if (data == PCI_VENDOR_DEVICE_GEODEGX)
73f29dbc25Smrg                    *cpu_revision = CIM_CPU_GEODEGX;
74f29dbc25Smrg                else
75f29dbc25Smrg                    *cpu_revision = CIM_CPU_GEODELX;
7604007ebaSmrg            }
7704007ebaSmrg            else if (data == PCI_VENDOR_5535 || data == PCI_VENDOR_5536) {
78f29dbc25Smrg                sb_found = 1;
79f29dbc25Smrg                if (data == PCI_VENDOR_5535)
80f29dbc25Smrg                    *companion_revision = CIM_SB_5535;
81f29dbc25Smrg                else
82f29dbc25Smrg                    *companion_revision = CIM_SB_5536;
83f29dbc25Smrg            }
84f29dbc25Smrg
85f29dbc25Smrg            if (cpu_found && sb_found)
86f29dbc25Smrg                break;
87f29dbc25Smrg        }
88f29dbc25Smrg        if (device != 21)
89f29dbc25Smrg            break;
90f29dbc25Smrg    }
91f29dbc25Smrg
92f29dbc25Smrg    if (bus == 256) {
93f29dbc25Smrg        *cpu_revision = 0;
94f29dbc25Smrg        return CIM_STATUS_CPUNOTFOUND;
95f29dbc25Smrg    }
96f29dbc25Smrg
97f29dbc25Smrg    msr_init_table();
98f29dbc25Smrg
99f29dbc25Smrg    if (msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_REVID,
10004007ebaSmrg                   &msr_value) != CIM_STATUS_OK) {
101f29dbc25Smrg        *cpu_revision = 0;
102f29dbc25Smrg        return CIM_STATUS_CPUNOTFOUND;
103f29dbc25Smrg    }
104f29dbc25Smrg
105f29dbc25Smrg    *cpu_revision |= ((msr_value.low & 0xF0) << 4) |
106f29dbc25Smrg        ((msr_value.low & 0x0F) << 16);
107f29dbc25Smrg
108f29dbc25Smrg    if (msr_read64(MSR_DEVICE_5535_GLCP, GLCP_REVID,
10904007ebaSmrg                   &msr_value) != CIM_STATUS_OK) {
110f29dbc25Smrg        *cpu_revision = 0;
111f29dbc25Smrg        return CIM_STATUS_CPUNOTFOUND;
112f29dbc25Smrg    }
113f29dbc25Smrg
114f29dbc25Smrg    *companion_revision |= ((msr_value.low & 0xF0) << 4) |
115f29dbc25Smrg        ((msr_value.low & 0x0F) << 16);
116f29dbc25Smrg
117f29dbc25Smrg    /* SEARCH ALL FUNCTIONS FOR INTEGRATED GRAPHICS */
118f29dbc25Smrg
119f29dbc25Smrg    num_bars = 0;
120f29dbc25Smrg    for (function = 0; function < 7; function++) {
121f29dbc25Smrg        address = 0x80000000 | (cpu_bus << 16) | (cpu_device << 11) |
122f29dbc25Smrg            (function << 8);
123f29dbc25Smrg        data = init_read_pci(address);
124f29dbc25Smrg
125f29dbc25Smrg        if (data == PCI_VENDOR_DEVICE_GEODEGX_VIDEO) {
126f29dbc25Smrg            num_bars = 4;
127f29dbc25Smrg            break;
12804007ebaSmrg        }
12904007ebaSmrg        else if (data == PCI_VENDOR_DEVICE_GEODELX_VIDEO) {
130f29dbc25Smrg            num_bars = 5;
131f29dbc25Smrg            break;
132f29dbc25Smrg        }
133f29dbc25Smrg    }
134f29dbc25Smrg
135f29dbc25Smrg    /* VERIFY THAT ALL BARS ARE PRESENT */
136f29dbc25Smrg
137f29dbc25Smrg    if (function == 7)
138f29dbc25Smrg        return CIM_STATUS_DISPLAYUNAVAILABLE;
139f29dbc25Smrg
140f29dbc25Smrg    for (i = 0; i < num_bars; i++) {
141f29dbc25Smrg        data = init_read_pci(address + 0x10 + (i << 2));
142f29dbc25Smrg
143f29dbc25Smrg        if (data == 0 || data == 0xFFFFFFFF)
144f29dbc25Smrg            break;
145f29dbc25Smrg    }
146f29dbc25Smrg
147f29dbc25Smrg    if (i != num_bars)
148f29dbc25Smrg        return CIM_STATUS_DISPLAYUNAVAILABLE;
149f29dbc25Smrg
150f29dbc25Smrg    /* SAVE VIDEO BASE ADDRESS FOR FUTURE CALLS */
151f29dbc25Smrg
152f29dbc25Smrg    init_video_base = address;
153f29dbc25Smrg
154f29dbc25Smrg    return CIM_STATUS_OK;
155f29dbc25Smrg}
156f29dbc25Smrg
157f29dbc25Smrg/*---------------------------------------------------------------------------
158f29dbc25Smrg * init_read_pci
159f29dbc25Smrg *
160f29dbc25Smrg * This routine reads an unsigned long value from a PCI address.
161f29dbc25Smrg *---------------------------------------------------------------------------*/
162f29dbc25Smrg
163f29dbc25Smrgunsigned long
164f29dbc25Smrginit_read_pci(unsigned long address)
165f29dbc25Smrg{
166f29dbc25Smrg    OUTD(0xCF8, address);
167f29dbc25Smrg    return IND(0xCFC);
168f29dbc25Smrg}
169f29dbc25Smrg
170f29dbc25Smrg/*---------------------------------------------------------------------------
171f29dbc25Smrg * init_read_base_addresses
172f29dbc25Smrg *
173f29dbc25Smrg * This routine reads all base addresses for the peripherals from the PCI
174f29dbc25Smrg * BARs.
175f29dbc25Smrg *---------------------------------------------------------------------------*/
176f29dbc25Smrg
177f29dbc25Smrgint
178f29dbc25Smrginit_read_base_addresses(INIT_BASE_ADDRESSES * base_addresses)
179f29dbc25Smrg{
180f29dbc25Smrg    unsigned long value;
181f29dbc25Smrg
182f29dbc25Smrg    /* READ ALL BASE ADDRESSES */
183f29dbc25Smrg
184f29dbc25Smrg    base_addresses->framebuffer_base = init_read_pci(init_video_base + 0x10);
185f29dbc25Smrg    base_addresses->gp_register_base = init_read_pci(init_video_base + 0x14);
186f29dbc25Smrg    base_addresses->vg_register_base = init_read_pci(init_video_base + 0x18);
187f29dbc25Smrg    base_addresses->df_register_base = init_read_pci(init_video_base + 0x1C);
188f29dbc25Smrg    base_addresses->vip_register_base = init_read_pci(init_video_base + 0x20);
189f29dbc25Smrg
190f29dbc25Smrg    /* READ FRAME BUFFER SIZE */
191f29dbc25Smrg    /* The frame buffer size is reported by a VSM in VSA II */
192f29dbc25Smrg    /* Virtual Register Class    = 0x02                    */
193f29dbc25Smrg    /* VG_MEM_SIZE (1MB units)   = 0x00                    */
194f29dbc25Smrg
195f29dbc25Smrg    OUTW(0xAC1C, 0xFC53);
196f29dbc25Smrg    OUTW(0xAC1C, 0x0200);
197f29dbc25Smrg
19804007ebaSmrg    value = (unsigned long) (INW(0xAC1E)) & 0xFE;
199f29dbc25Smrg
200f29dbc25Smrg    base_addresses->framebuffer_size = value << 20;
201f29dbc25Smrg
202f29dbc25Smrg    return CIM_STATUS_OK;
203f29dbc25Smrg}
204f29dbc25Smrg
205f29dbc25Smrg/*---------------------------------------------------------------------------
206f29dbc25Smrg * init_read_cpu_frequency
207f29dbc25Smrg *
208f29dbc25Smrg * This routine returns the current CPU core frequency, in MHz.
209f29dbc25Smrg *---------------------------------------------------------------------------*/
210f29dbc25Smrg
211f29dbc25Smrgint
212f29dbc25Smrginit_read_cpu_frequency(unsigned long *cpu_frequency)
213f29dbc25Smrg{
214f29dbc25Smrg    /* CPU SPEED IS REPORTED BY A VSM IN VSA II */
215f29dbc25Smrg    /* Virtual Register Class = 0x12 (Sysinfo)  */
216f29dbc25Smrg    /* CPU Speed Register     = 0x01            */
217f29dbc25Smrg
218f29dbc25Smrg    OUTW(0xAC1C, 0xFC53);
219f29dbc25Smrg    OUTW(0xAC1C, 0x1201);
220f29dbc25Smrg
22104007ebaSmrg    *cpu_frequency = (unsigned long) (INW(0xAC1E));
222f29dbc25Smrg
223f29dbc25Smrg    return CIM_STATUS_OK;
224f29dbc25Smrg}
225