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