1/* Copyright (c) 2005 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 *
21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 * */
25
26/*
27 * File Contents:   This file contains platform dependent functions
28 *                  which provide interface to that platform.
29 *
30 * SubModule:       Geode FlatPanel library
31 * */
32
33#define LINUX_ROM_SEGMENT 0x000F
34#define SEGMENT_LENGTH  0xFFFF
35#define PAGE_LENGTH     0x1000
36#define SYS_BOARD_NAME_LEN 24
37
38#define PLT_UNKNOWN     0xFFFF
39
40typedef struct {
41    char sys_board_name[SYS_BOARD_NAME_LEN];
42    SYS_BOARD sys_board;
43} SYS_BOARD_INFO;
44
45static SYS_BOARD_INFO Sys_info;
46
47/*
48 * The names in the sys_board_name string must exactly match the names in the
49 * BIOS header. These names are used by FindStringInSeg() to find the names
50 * in the BIOS header space. The BIOS does not use OTHER; it is a dummy value
51 * for program useonly.
52 */
53
54SYS_BOARD_INFO Sys_board_info_array[] = {
55    {"Marmot", MARMOT_PLATFORM},
56    {"Unicorn", UNICORN_PLATFORM},
57    {"Centaurus", CENTAURUS_PLATFORM},
58    {"Aries", ARIES_PLATFORM},
59    {"Carmel", CARMEL_PLATFORM},
60    {"Hyrda", HYDRA_PLATFORM},
61    {"Dorado", DORADO_PLATFORM},
62    {"Redcloud", REDCLOUD_PLATFORM},
63    {"Other", OTHER_PLATFORM}
64};
65
66#define NUM_SYS_BOARD_TYPES		\
67		sizeof(Sys_board_info_array)/sizeof(SYS_BOARD_INFO)
68
69static int Num_sys_board_type = NUM_SYS_BOARD_TYPES;
70SYS_BOARD_INFO *Sys_board_array_base = Sys_board_info_array;
71int FindStringInSeg(unsigned int, char *);
72static unsigned char get_sys_board_type(SYS_BOARD_INFO *, SYS_BOARD_INFO *);
73
74/* Detect the Platform */
75int
76Detect_Platform(void)
77{
78    /* See if we can find the board name using Xpressrom */
79    get_sys_board_type(&Sys_info, Sys_board_array_base);
80    return (Sys_info.sys_board);
81}
82
83static int
84Strncmp(char *str1, char *str2, int len)
85{
86    int i;
87
88    if ((str1 == 0x0) || (str2 == 0x0) || (len == 0))
89        return (1);
90    for (i = 0; i < len; i++) {
91        if (*(str1 + i) > *(str2 + i)) {
92            return 1;
93        }
94        else if (*(str1 + i) < *(str2 + i)) {
95            return -1;
96        }
97    }
98    return 0;
99}
100
101static char *
102Strcpy(char *dst, char *src)
103{
104    int i;
105
106    if ((dst == 0x0) || (src == 0x0))
107        return (0);
108    for (i = 0; src[i] != 0x0; i++) {
109        dst[i] = src[i];
110    }
111    dst[i] = 0x0;               /* NULL termination */
112    return dst;
113}
114
115static int
116Strlen(char *str)
117{
118    int i;
119
120    if (str == 0x0)
121        return 0;
122    for (i = 0; str[i] != 0x0; i++);
123    return i;
124}
125
126/* Platform Detection Code */
127
128/************************************************************************
129 * int FindStringInSeg( unsigned int segment_address, char *string_ptr )
130 *
131 * Returns the offset where the NULL terminated string pointed to by
132 * string_ptr is located in the segment passed in segment_address.
133 * Segment_address must be of the form 0xXXXX (i.e 0xf000 for segment f).
134 * Returns NULL if the string is not found.
135 ************************************************************************
136 */
137int
138FindStringInSeg(unsigned int segment_address, char *string_ptr)
139{
140    int string_length = Strlen(string_ptr);
141    char *psegment_buf;
142    unsigned long mem_ptr = (unsigned long) segment_address << 16;
143    unsigned int i;
144
145    /* silence compiler */
146    (void) mem_ptr;
147
148    psegment_buf = (char *) XpressROMPtr;
149
150    /* Now search for the first character of the string_ptr */
151    for (i = 0; i < SEGMENT_LENGTH + 1; i++) {
152        if (*(psegment_buf + i) == *string_ptr) {
153
154            /* If we match the first character, do a
155             * string compare.
156             */
157
158            if (!Strncmp(string_ptr, (psegment_buf + i), string_length)) {
159                /* They match! */
160                return (1);
161            }
162        }
163    }
164    /* if we got this far we didn't find anything.  Return NULL. */
165    return (0);
166
167}                               /* end FindStringInSeg() */
168
169/**********************************************************************
170
171 * TRUE_FALSE get_sys_board_type( SYS_BOARD_INFO *sys_info,
172 * SYS_BOARD_INFO *sys_board_array_base)
173 *
174 * Checks the system BIOS area for Xpressrom information. If found, searches
175 * the  BIOS area for one of names in the array pointed to by
176 * sys_board_array_ptr.
177 * If a match is found, sets the SYS_INFO system_board_name string
178 * and the system_board variable to the board name and returns TRUE.
179 * If Xpressrom or a board is not found, sets the variables to
180 * their default values and returns FALSE.
181 * Uses the global string pointer *xpress_rom_string_ptr.
182 ***********************************************************************
183 */
184static unsigned char
185get_sys_board_type(SYS_BOARD_INFO * sys_info,
186                   SYS_BOARD_INFO * sys_board_array_base)
187{
188    int index;
189    char *xpress_rom_string_ptr = "XpressStart";
190    unsigned int segment = LINUX_ROM_SEGMENT;
191
192    /* See if XpressStart is present in the BIOS area.
193     * If it is, search for a board string.  If not, Xpressrom is
194     * not present, set system_board information to UNKNOWN and
195     * return FALSE.
196     */
197
198    if (!FindStringInSeg(segment, xpress_rom_string_ptr)) {
199        sys_info->sys_board = PLT_UNKNOWN;
200        Strcpy(sys_info->sys_board_name, "Unknown");
201        return (FALSE);
202    }
203    else {
204
205        /* we have Xpressrom, so look for a board */
206        for (index = 0; index < Num_sys_board_type; index++) {
207            if (!FindStringInSeg(segment, (sys_board_array_base +
208                                           index)->sys_board_name)) {
209                continue;
210            }
211            else {
212
213                /* a match!! */
214                sys_info->sys_board = (sys_board_array_base + index)->sys_board;
215                Strcpy(sys_info->sys_board_name,
216                       (sys_board_array_base + index)->sys_board_name);
217                return (TRUE);
218            }
219        }                       /* end for() */
220    }                           /* end else */
221
222    /* if we are here we have failed */
223    sys_info->sys_board = PLT_UNKNOWN;
224    Strcpy(sys_info->sys_board_name, "Unknown");
225    return (FALSE);
226}                               /* end get_sys_board_type() */
227