cim_init.c revision 04007eba
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, unsigned long *companion_revision)
47{
48    unsigned long bus, device, i;
49    unsigned long cpu_bus = 0, cpu_device = 0;
50    unsigned long address, data;
51    unsigned long num_bars, function;
52    int cpu_found, sb_found;
53    Q_WORD msr_value;
54
55    /* SEARCH THROUGH PCI BUS                                          */
56    /* We search the PCI bus for the Geode LX or Geode GX northbridge. */
57    /* We then verify that one of its functions is the graphics        */
58    /* controller and that all bars are filled in.                     */
59
60    cpu_found = sb_found = 0;
61    for (bus = 0; bus < 256; bus++) {
62        for (device = 0; device < 21; device++) {
63            address = 0x80000000 | (bus << 16) | (device << 11);
64
65            data = init_read_pci(address);
66
67            if (data == PCI_VENDOR_DEVICE_GEODEGX
68                || data == PCI_VENDOR_DEVICE_GEODELX) {
69                cpu_found = 1;
70                cpu_device = device;
71                cpu_bus = bus;
72                if (data == PCI_VENDOR_DEVICE_GEODEGX)
73                    *cpu_revision = CIM_CPU_GEODEGX;
74                else
75                    *cpu_revision = CIM_CPU_GEODELX;
76            }
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        }
129        else if (data == PCI_VENDOR_DEVICE_GEODELX_VIDEO) {
130            num_bars = 5;
131            break;
132        }
133    }
134
135    /* VERIFY THAT ALL BARS ARE PRESENT */
136
137    if (function == 7)
138        return CIM_STATUS_DISPLAYUNAVAILABLE;
139
140    for (i = 0; i < num_bars; i++) {
141        data = init_read_pci(address + 0x10 + (i << 2));
142
143        if (data == 0 || data == 0xFFFFFFFF)
144            break;
145    }
146
147    if (i != num_bars)
148        return CIM_STATUS_DISPLAYUNAVAILABLE;
149
150    /* SAVE VIDEO BASE ADDRESS FOR FUTURE CALLS */
151
152    init_video_base = address;
153
154    return CIM_STATUS_OK;
155}
156
157/*---------------------------------------------------------------------------
158 * init_read_pci
159 *
160 * This routine reads an unsigned long value from a PCI address.
161 *---------------------------------------------------------------------------*/
162
163unsigned long
164init_read_pci(unsigned long address)
165{
166    OUTD(0xCF8, address);
167    return IND(0xCFC);
168}
169
170/*---------------------------------------------------------------------------
171 * init_read_base_addresses
172 *
173 * This routine reads all base addresses for the peripherals from the PCI
174 * BARs.
175 *---------------------------------------------------------------------------*/
176
177int
178init_read_base_addresses(INIT_BASE_ADDRESSES * base_addresses)
179{
180    unsigned long value;
181
182    /* READ ALL BASE ADDRESSES */
183
184    base_addresses->framebuffer_base = init_read_pci(init_video_base + 0x10);
185    base_addresses->gp_register_base = init_read_pci(init_video_base + 0x14);
186    base_addresses->vg_register_base = init_read_pci(init_video_base + 0x18);
187    base_addresses->df_register_base = init_read_pci(init_video_base + 0x1C);
188    base_addresses->vip_register_base = init_read_pci(init_video_base + 0x20);
189
190    /* READ FRAME BUFFER SIZE */
191    /* The frame buffer size is reported by a VSM in VSA II */
192    /* Virtual Register Class    = 0x02                    */
193    /* VG_MEM_SIZE (1MB units)   = 0x00                    */
194
195    OUTW(0xAC1C, 0xFC53);
196    OUTW(0xAC1C, 0x0200);
197
198    value = (unsigned long) (INW(0xAC1E)) & 0xFE;
199
200    base_addresses->framebuffer_size = value << 20;
201
202    return CIM_STATUS_OK;
203}
204
205/*---------------------------------------------------------------------------
206 * init_read_cpu_frequency
207 *
208 * This routine returns the current CPU core frequency, in MHz.
209 *---------------------------------------------------------------------------*/
210
211int
212init_read_cpu_frequency(unsigned long *cpu_frequency)
213{
214    /* CPU SPEED IS REPORTED BY A VSM IN VSA II */
215    /* Virtual Register Class = 0x12 (Sysinfo)  */
216    /* CPU Speed Register     = 0x01            */
217
218    OUTW(0xAC1C, 0xFC53);
219    OUTW(0xAC1C, 0x1201);
220
221    *cpu_frequency = (unsigned long) (INW(0xAC1E));
222
223    return CIM_STATUS_OK;
224}
225