1/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nsc/gfx/msr_rdcl.c,v 1.1 2002/12/10 15:12:27 alanh Exp $ */
2/*
3 * $Workfile: msr_rdcl.c $
4 *
5 * This file contains MSR access routines for Redcloud.
6 *
7 * NSC_LIC_ALTERNATIVE_PREAMBLE
8 *
9 * Revision 1.0
10 *
11 * National Semiconductor Alternative GPL-BSD License
12 *
13 * National Semiconductor Corporation licenses this software
14 * ("Software"):
15 *
16 *      Durango
17 *
18 * under one of the two following licenses, depending on how the
19 * Software is received by the Licensee.
20 *
21 * If this Software is received as part of the Linux Framebuffer or
22 * other GPL licensed software, then the GPL license designated
23 * NSC_LIC_GPL applies to this Software; in all other circumstances
24 * then the BSD-style license designated NSC_LIC_BSD shall apply.
25 *
26 * END_NSC_LIC_ALTERNATIVE_PREAMBLE */
27
28/* NSC_LIC_BSD
29 *
30 * National Semiconductor Corporation Open Source License for Durango
31 *
32 * (BSD License with Export Notice)
33 *
34 * Copyright (c) 1999-2001
35 * National Semiconductor Corporation.
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 *
42 *   * Redistributions of source code must retain the above copyright
43 *     notice, this list of conditions and the following disclaimer.
44 *
45 *   * Redistributions in binary form must reproduce the above
46 *     copyright notice, this list of conditions and the following
47 *     disclaimer in the documentation and/or other materials provided
48 *     with the distribution.
49 *
50 *   * Neither the name of the National Semiconductor Corporation nor
51 *     the names of its contributors may be used to endorse or promote
52 *     products derived from this software without specific prior
53 *     written permission.
54 *
55 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
56 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
57 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
58 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
59 * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY
60 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
62 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
63 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
64 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE,
65 * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY
66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
67 * OF SUCH DAMAGE.
68 *
69 * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
70 * YOUR JURISDICTION. It is licensee's responsibility to comply with
71 * any export regulations applicable in licensee's jurisdiction. Under
72 * CURRENT (2001) U.S. export regulations this software
73 * is eligible for export from the U.S. and can be downloaded by or
74 * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed
75 * destinations which include Cuba, Iraq, Libya, North Korea, Iran,
76 * Syria, Sudan, Afghanistan and any other country to which the U.S.
77 * has embargoed goods and services.
78 *
79 * END_NSC_LIC_BSD */
80
81/* NSC_LIC_GPL
82 *
83 * National Semiconductor Corporation Gnu General Public License for Durango
84 *
85 * (GPL License with Export Notice)
86 *
87 * Copyright (c) 1999-2001
88 * National Semiconductor Corporation.
89 * All rights reserved.
90 *
91 * Redistribution and use in source and binary forms, with or without
92 * modification, are permitted under the terms of the GNU General
93 * Public License as published by the Free Software Foundation; either
94 * version 2 of the License, or (at your option) any later version
95 *
96 * In addition to the terms of the GNU General Public License, neither
97 * the name of the National Semiconductor Corporation nor the names of
98 * its contributors may be used to endorse or promote products derived
99 * from this software without specific prior written permission.
100 *
101 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
102 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
103 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
104 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
105 * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY
106 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
107 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
108 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
109 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
110 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE,
111 * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY
112 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
113 * OF SUCH DAMAGE. See the GNU General Public License for more details.
114 *
115 * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
116 * YOUR JURISDICTION. It is licensee's responsibility to comply with
117 * any export regulations applicable in licensee's jurisdiction. Under
118 * CURRENT (2001) U.S. export regulations this software
119 * is eligible for export from the U.S. and can be downloaded by or
120 * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed
121 * destinations which include Cuba, Iraq, Libya, North Korea, Iran,
122 * Syria, Sudan, Afghanistan and any other country to which the U.S.
123 * has embargoed goods and services.
124 *
125 * You should have received a copy of the GNU General Public License
126 * along with this file; if not, write to the Free Software Foundation,
127 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
128 *
129 * END_NSC_LIC_GPL */
130
131int redcloud_msr_init(void);
132DEV_STATUS redcloud_id_msr_device(MSR * pDev, unsigned long address);
133DEV_STATUS redcloud_get_msr_dev_address(unsigned int device,
134					unsigned long *address);
135DEV_STATUS redcloud_get_glink_id_at_address(unsigned int *device,
136					    unsigned long address);
137DEV_STATUS redcloud_msr_read(unsigned int device, unsigned int msrRegister,
138			     Q_WORD * msrValue);
139DEV_STATUS redcloud_msr_write(unsigned int device, unsigned int msrRegister,
140			      Q_WORD * msrValue);
141
142void redcloud_build_mbus_tree(void);	/* private routine definition */
143int redcloud_init_msr_devices(MSR aDev[], unsigned int array_size);	/* private routine definition */
144DEV_STATUS redcloud_find_msr_device(MSR * pDev);	/* private routine definition */
145
146/* REDCLOUD MSR BITMASKS */
147
148#define MBD_MSR_CAP			0x2000
149#define MSR_CAP_ID_MASK		0xFF000
150#define MSR_CAP_ID_SHIFT  	12
151#define MSR_CAP_REV_MASK    0x0F
152#define MBIU_CAP			0x86
153#define NUM_PORTS_MASK		0x00380000
154#define NUM_PORTS_SHIFT  	19
155#define MBIU_WHOAMI			0x8B
156#define WHOAMI_MASK			0x07
157
158/* REDCLOUD and CS5535 MSR DEVICES */
159
160MSR msrDev[] = {
161   {FOUND, RC_CC_MBIU, RC_MB0_MBIU0},
162   {FOUND, RC_CC_MBIU, RC_MB0_MBIU1},
163   {NOT_KNOWN, RC_CC_MCP, FAKE_ADDRESS},
164   {NOT_KNOWN, RC_CC_MPCI, FAKE_ADDRESS},
165   {NOT_KNOWN, RC_CC_MC, FAKE_ADDRESS},
166   {NOT_KNOWN, RC_CC_GP, FAKE_ADDRESS},
167   {NOT_KNOWN, RC_CC_VG, FAKE_ADDRESS},
168   {NOT_KNOWN, RC_CC_DF, FAKE_ADDRESS},
169   {NOT_KNOWN, RC_CC_FG, FAKE_ADDRESS},
170   {FOUND, RC_CC_VA, RC_MB0_CPU},
171   {FOUND, CP_CC_MBIU, CP_MB0_MBIU0},
172   {NOT_KNOWN, CP_CC_MPCI, FAKE_ADDRESS},
173   {NOT_KNOWN, CP_CC_USB2, FAKE_ADDRESS},
174   {NOT_KNOWN, CP_CC_ATAC, FAKE_ADDRESS},
175   {NOT_KNOWN, CP_CC_MDD, FAKE_ADDRESS},
176   {NOT_KNOWN, CP_CC_ACC, FAKE_ADDRESS},
177   {NOT_KNOWN, CP_CC_USB1, FAKE_ADDRESS},
178   {NOT_KNOWN, CP_CC_MCP, FAKE_ADDRESS},
179};
180
181#define NUM_DEVS sizeof(msrDev) / sizeof(struct msr)
182
183/* CAPISTRANO DEVICE INDEX LIMITS */
184/* These defines represent the start and stop indexes into the device array  */
185/* for all Capistrano devices.  These should be updated whenever a device is */
186/* added or removed to the Capistrano list.                                  */
187
188#define CP_INDEX_START CP_ID_MBIU
189#define CP_INDEX_STOP  CP_ID_MCP
190
191/* GLOBAL MBUS CACHE STRUCTURES */
192/* These structures contain a "cached" copy of the MBUS topology */
193/* for easy future lookup.                                       */
194
195MBUS_NODE MBIU0[8], MBIU1[8], MBIU2[8];
196
197/* REGISTER MACROS */
198
199#define GET_DEVICE_ID( CAPABILITIES_HIGH, CAPABILITIES_LOW ) \
200					 ((unsigned int)(( (CAPABILITIES_LOW) & MSR_CAP_ID_MASK ) >> MSR_CAP_ID_SHIFT ))
201
202#define GET_NUM_PORTS( MBIU_CAP_HIGH, MBIU_CAP_LOW ) (((MBIU_CAP_HIGH) & NUM_PORTS_MASK ) >> NUM_PORTS_SHIFT)
203
204/*-----------------------------------------------------------------------------
205 * gfx_msr_init
206 *
207 * This routine initializes the base addresses of all known MBUS devices.
208 *-----------------------------------------------------------------------------
209 */
210#if GFX_MSR_DYNAMIC
211int
212redcloud_msr_init(void)
213#else
214int
215gfx_msr_init(void)
216#endif
217{
218   Q_WORD msrValue;
219   int return_value = 1;
220
221   /* CHECK FOR VALID MBUS CONFIGURATION */
222   /* The CPU and the two MBIUs are assumed to be at known static addresses, so */
223   /* we will check the device IDs at these addresses as proof of a valid mbus  */
224   /* configuration.                                                            */
225
226   MSR_READ(MBD_MSR_CAP, RC_MB0_CPU, &(msrValue.high), &(msrValue.low));
227   if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_VA)
228      return_value = 0;
229
230   MSR_READ(MBD_MSR_CAP, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
231   if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_MBIU)
232      return_value = 0;
233
234   MSR_READ(MBD_MSR_CAP, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low));
235   if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_MBIU)
236      return_value = 0;
237
238   /* ENUMERATE VALID BUS */
239   /* If all static devices were identified, continue with the enumeration */
240
241   if (return_value) {
242      /* OPTIMIZATION */
243      /* Build a local copy of the MBUS topology.  This allows us to  */
244      /* quickly search the entire MBUS for a given device ID without */
245      /* repeated MSR accesses.                                       */
246
247      redcloud_build_mbus_tree();
248
249      /* INITIALIZE MSR DEVICES */
250
251      return_value = redcloud_init_msr_devices(msrDev, NUM_DEVS);
252
253   }
254
255   return return_value;
256
257}
258
259/*--------------------------------------------------------------------------
260 * void	redcloud_build_mbus_tree() (PRIVATE ROUTINE - NOT PART OF DURANGO API)
261 *
262 * This routine walks through the MBUS and records the address value and
263 * device ID found at each node.  If a node (aka port) is not populated,
264 * that node returns '0'.  The deviceID for that node is set to '0'
265 * (NOT_POPULATED) to reflect this. If the node being queried points back to
266 * Vail or MBIU0, the deviceID for that node is set to 'REFLECTIVE'.  Reflective
267 * nodes are nodes that forward the given MBUS address BACK to the initiator.
268 *-----------------------------------------------------------------------------
269 */
270void
271redcloud_build_mbus_tree(void)
272{
273   unsigned long mbiu_port_count, reflective;
274   unsigned long port;
275   Q_WORD msrValue;
276
277   /*                  */
278   /* ENUMERATE MBIU0  */
279   /*                  */
280
281   /* COUNT MBIU PORTS */
282
283   MSR_READ(MBIU_CAP, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
284   mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low);
285
286   /* FIND REFLECTIVE PORT */
287   /* Query the MBIU for the port through which we are communicating. */
288   /* We will avoid accesses to this port to avoid a self-reference.  */
289
290   MSR_READ(MBIU_WHOAMI, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
291   reflective = msrValue.low & WHOAMI_MASK;
292
293   /* ENUMERATE ALL PORTS */
294   /* For every possible port, set the MBIU.deviceId to something. */
295
296   for (port = 0; port < 8; port++) {
297      /* FILL IN CLAIMED FIELD */
298      /* All MBIU ports can only be assigned to one device from the */
299      /* Durango table                                              */
300
301      MBIU0[port].claimed = 0;
302
303      /* MBIU0 PORT NUMBERS ARE IN ADDRESS BITS 31:29 */
304
305      MBIU0[port].address = port << 29;
306
307      /* SPECIAL CASE FOR MBIU0 */
308      /* MBIU0 port 0 is a special case, as it points back to MBIU0.  MBIU0 */
309      /* responds at address 0x40000xxx, which does not equal 0 << 29.      */
310
311      if (port == 0)
312	 MBIU0[port].deviceId = RC_CC_MBIU;
313      else if (port == reflective)
314	 MBIU0[port].deviceId = REFLECTIVE;
315      else if (port > mbiu_port_count)
316	 MBIU0[port].deviceId = NOT_POPULATED;
317      else {
318	 MSR_READ(MBD_MSR_CAP, MBIU0[port].address, &(msrValue.high),
319		  &(msrValue.low));
320	 MBIU0[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low);
321      }
322   }
323
324   /*                  */
325   /* ENUMERATE MBIU1  */
326   /*                  */
327
328   /* COUNT MBIU PORTS */
329
330   MSR_READ(MBIU_CAP, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low));
331   mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low);
332
333   /* FIND REFLECTIVE PORT */
334   /* Query the MBIU for the port through which we are communicating. */
335   /* We will avoid accesses to this port to avoid a self-reference.  */
336
337   MSR_READ(MBIU_WHOAMI, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low));
338   reflective = msrValue.low & WHOAMI_MASK;
339
340   /* ENUMERATE ALL PORTS */
341   /* For every possible port, set the MBIU.deviceId to something. */
342
343   for (port = 0; port < 8; port++) {
344      /* FILL IN CLAIMED FIELD */
345      /* All MBIU ports can only be assigned to one device from the */
346      /* Durango table                                              */
347
348      MBIU1[port].claimed = 0;
349
350      /* MBIU1 PORT NUMBERS ARE IN 28:26 AND 31:29 = 010B */
351
352      MBIU1[port].address = (0x02l << 29) + (port << 26);
353
354      if (port == reflective)
355	 MBIU1[port].deviceId = REFLECTIVE;
356      else if (port > mbiu_port_count)
357	 MBIU1[port].deviceId = NOT_POPULATED;
358      else {
359	 MSR_READ(MBD_MSR_CAP, MBIU1[port].address, &(msrValue.high),
360		  &(msrValue.low));
361	 MBIU1[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low);
362      }
363   }
364
365   /*                          */
366   /* ENUMERATE MBIU2 (CS5535) */
367   /*  (if present)            */
368
369   MSR_READ(MBD_MSR_CAP, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
370   if (GET_DEVICE_ID(msrValue.high, msrValue.low) == CP_CC_MBIU) {
371      /* COUNT MBIU PORTS */
372
373      MSR_READ(MBIU_CAP, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
374      mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low);
375
376      /* FIND REFLECTIVE PORT */
377      /* Query the MBIU for the port through which we are communicating. */
378      /* We will avoid accesses to this port to avoid a self-reference.  */
379
380      MSR_READ(MBIU_WHOAMI, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
381      reflective = msrValue.low & WHOAMI_MASK;
382
383      /* ENUMERATE ALL PORTS */
384      /* For every possible port, set the MBIU.deviceId to something. */
385
386      for (port = 0; port < 8; port++) {
387	 /* FILL IN CLAIMED FIELD */
388	 /* All MBIU ports can only be assigned to one device from the */
389	 /* Durango table                                              */
390
391	 MBIU2[port].claimed = 0;
392
393	 /* MBIU2 PORT NUMBERS ARE IN 22:20 AND 31:23 = 010100010B */
394
395	 MBIU2[port].address =
396	       (0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20);
397
398	 if (port == reflective)
399	    MBIU2[port].deviceId = REFLECTIVE;
400	 else if (port > mbiu_port_count)
401	    MBIU2[port].deviceId = NOT_POPULATED;
402	 else {
403	    MSR_READ(MBD_MSR_CAP, MBIU2[port].address, &(msrValue.high),
404		     &(msrValue.low));
405	    MBIU2[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low);
406	 }
407      }
408   } else {
409      /* NO 5535                                                  */
410      /* If the CS5535 is not installed, fill in the cached table */
411      /* with the 'NOT_INSTALLED' flag.  Also, fill in the device */
412      /* status from NOT_KNOWN to REQ_NOT_INSTALLED.              */
413
414      for (port = 0; port < 8; port++) {
415	 MBIU2[port].claimed = 0;
416	 MBIU2[port].deviceId = NOT_INSTALLED;
417	 MBIU2[port].address =
418	       (0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20);
419      }
420      for (port = CP_INDEX_START; port <= CP_INDEX_STOP; port++) {
421	 msrDev[port].Present = REQ_NOT_INSTALLED;
422      }
423   }
424}
425
426/*------------------------------------------------------------------
427 * redcloud_init_msr_devices (PRIVATE ROUTINE - NOT PART OF DURANGO API)
428
429 * Handles the details of finding each possible device on the MBUS.
430 * If a given device is not found, its structure is left uninitialized.
431 * If a given device is found, its structure is updated.
432 *
433 * This init routine only checks for devices in aDev[].
434 *
435 *  Passed:
436 *		aDev - is a pointer to the array of MBUS devices.
437 *		arraySize - number of elements in aDev.
438 *
439 *	Returns:
440 *		1 - If, for every device, its address was found.
441 *		0 - If, for any device, an error was encountered.
442 *------------------------------------------------------------------
443 */
444int
445redcloud_init_msr_devices(MSR aDev[], unsigned int array_size)
446{
447   unsigned int i, issues = 0;
448
449   /* TRY TO FIND EACH ITEM IN THE ARRAY */
450
451   for (i = 0; i < array_size; i++) {
452      /* IGNORE DEVICES THAT ARE ALREADY FOUND                */
453      /* The addresses for "found" devices are already known. */
454
455      if (aDev[i].Present == FOUND || aDev[i].Present == REQ_NOT_INSTALLED)
456	 continue;
457
458      /* TRY TO FIND THE DEVICE ON THE MBUS */
459
460      aDev[i].Present = redcloud_find_msr_device(&aDev[i]);
461
462      /* INCREMENT ERROR COUNT IF DEVICE NOT FOUND */
463
464      if (aDev[i].Present != FOUND)
465	 issues++;
466   }
467
468   return (issues == 0);
469}
470
471/*------------------------------------------------------------------
472 *  redcloud_find_msr_device (PRIVATE ROUTINE - NOT PART OF DURANGO API)
473 *
474 *  Passed:
475 *	    pDev - is a pointer to one element in the array of MBUS devices
476 *
477 *  Returns:
478 *	    FOUND - Device was found and pDev->Address has been updated.
479 *
480 *		REQ_NOT_FOUND - Device was not found and pDev->Address has not
481 *						been updated.
482 *
483 *------------------------------------------------------------------
484*/
485DEV_STATUS
486redcloud_find_msr_device(MSR * pDev)
487{
488   unsigned int i;
489
490   /* SEARCH DURANGO'S CACHED MBUS TOPOLOGY */
491   /* This gets a little tricky.  As the only identifier we have for each   */
492   /* device is the device ID and we have multiple devices of the same type */
493   /* MCP, MPCI, USB, etc. we need to make some assumptions based on table  */
494   /* order.  These are as follows:                                         */
495   /* 1. All Redcloud nodes are searched first, as we assume that they      */
496   /*    are first in the table.                                            */
497   /* 2. If two devices have the same device ID and are found on the same   */
498   /*    device (GX2, CS5535, etc.) we assume that they are listed such     */
499   /*    that the first device in the table with this device ID has a lower */
500   /*    port address.                                                      */
501   /* 3. After a device ID has been matched, the port is marked as          */
502   /*    'claimed', such that future enumerations continue searching the    */
503   /*    GeodeLink topology.                                                */
504
505   /* SEARCH MBIU0 */
506
507   for (i = 0; i < 8; i++) {
508      if (MBIU0[i].deviceId == pDev->Id && !(MBIU0[i].claimed)) {
509	 MBIU0[i].claimed = 1;
510	 pDev->Address = MBIU0[i].address;
511	 return FOUND;
512      }
513   }
514
515   /* SEARCH MBIU1 */
516
517   for (i = 0; i < 8; i++) {
518      if (MBIU1[i].deviceId == pDev->Id && !(MBIU1[i].claimed)) {
519	 MBIU1[i].claimed = 1;
520	 pDev->Address = MBIU1[i].address;
521	 return FOUND;
522      }
523   }
524
525   /* SEARCH MBIU2 */
526
527   for (i = 0; i < 8; i++) {
528      if (MBIU2[i].deviceId == pDev->Id && !(MBIU2[i].claimed)) {
529	 MBIU2[i].claimed = 1;
530	 pDev->Address = MBIU2[i].address;
531	 return FOUND;
532      }
533   }
534
535   return REQ_NOT_FOUND;
536}
537
538/*--------------------------------------------------------------------
539 * gfx_id_msr_device
540 *
541 *	This routine handles reading the capabilities MSR register (typically 0x2000)
542 *	and checking if the 'id' field matchs  pDev.Id.  This routine is
543 *  used by applications/drivers that need to extend the list of known
544 *  MBUS devices beyond those known by Durango.
545 *
546 *		Passed:
547 *			pDev - Pointer to MSR structure containing the device's ID.
548 *		    address - device address.
549 *
550 *		Returns:
551 *			FOUND - The IDs do match.
552 *			REQ_NOT_FOUND - There was not a match.
553 *
554 *--------------------------------------------------------------------
555 */
556#if GFX_MSR_DYNAMIC
557DEV_STATUS
558redcloud_id_msr_device(MSR * pDev, unsigned long address)
559#else
560DEV_STATUS
561gfx_id_msr_device(MSR * pDev, unsigned long address)
562#endif
563{
564   Q_WORD msrValue;
565
566   MSR_READ(MBD_MSR_CAP, address, &(msrValue.high), &(msrValue.low));
567
568   if (GET_DEVICE_ID(msrValue.high, msrValue.low) == pDev->Id)
569      return FOUND;
570   else
571      return REQ_NOT_FOUND;
572}
573
574/*--------------------------------------------------------------------
575 * gfx_get_msr_dev_address
576 *
577 * This function returns the 32-bit address of the requested device.
578 * The device must be a known MBUS device.  (It must be in Durango's
579 * device table.)  DEV_STATUS should be checked to verify that the address
580 * was updated.
581 *
582 *
583 * Passed:
584 *     device - device index of the device in question.
585 *	   *address - ptr to location where address should be stored.
586 *
587 * Returns:
588 *	   DEV_STATUS of device in question.  (NOT_KNOWN if device is out of range.)
589 *     *address - updated if 'device' is within range
590 *
591 *	Notes:
592 *     This function should only be called after gfx_msr_init
593 *
594 *--------------------------------------------------------------------
595 */
596#if GFX_MSR_DYNAMIC
597DEV_STATUS
598redcloud_get_msr_dev_address(unsigned int device, unsigned long *address)
599#else
600DEV_STATUS
601gfx_get_msr_dev_address(unsigned int device, unsigned long *address)
602#endif
603{
604   if (device < NUM_DEVS) {
605      if (msrDev[device].Present == FOUND)
606	 *address = msrDev[device].Address;
607
608      return msrDev[device].Present;
609   }
610   return NOT_KNOWN;
611
612}
613
614/*--------------------------------------------------------------------
615 *  gfx_get_glink_id_at_address
616 *
617 *	This function returns the 16-bit deviceId at the requested address.
618 *  DEV_STATUS should be checked to make sure that device was updated.
619 *
620 *	Passed:
621 *	    device - ptr to location where device ID should be stored.
622 *		address - address of desired device ID.
623 *
624 *  Returns:
625 *	    FOUND if address is a valid address, NOT_KNOWN if address cannot be found
626 *      on the mbus.
627 *      *device - updated with device Id info.
628 *
629 *	Notes:
630 *      This function should be called after gfx_msr_init
631 *
632 *--------------------------------------------------------------------
633 */
634#if GFX_MSR_DYNAMIC
635DEV_STATUS
636redcloud_get_glink_id_at_address(unsigned int *device, unsigned long address)
637#else
638DEV_STATUS
639gfx_get_glink_id_at_address(unsigned int *device, unsigned long address)
640#endif
641{
642   int port;
643
644   for (port = 0; port < 8; port++) {
645      if (MBIU0[port].address == address) {
646	 *device = MBIU0[port].deviceId;
647	 return FOUND;
648      } else if (MBIU1[port].address == address) {
649	 *device = MBIU1[port].deviceId;
650	 return FOUND;
651      } else if (MBIU2[port].address == address) {
652	 *device = MBIU2[port].deviceId;
653	 return FOUND;
654      }
655   }
656
657   return NOT_KNOWN;
658
659}
660
661/*--------------------------------------------------------------------
662 * gfx_msr_read
663 *
664 * Performs a 64-bit read from 'msrRegister' in device 'device'.  'device' is
665 * an index into Durango's table of known MBUS devices.
666 *
667 * Returns:
668 *     FOUND - if no errors were detected and msrValue has been updated.
669 *	   NOT_KNOWN	- an error was detected.  msrValue is not updated.
670 *	   REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown.  Caller
671 *						should call msrInit() first.  msrValue is not updated.
672 *	   Notes:
673 *         This function should be called after gfx_msr_init
674 *--------------------------------------------------------------------
675 */
676#if GFX_MSR_DYNAMIC
677DEV_STATUS
678redcloud_msr_read(unsigned int device, unsigned int msrRegister,
679		  Q_WORD * msrValue)
680#else
681DEV_STATUS
682gfx_msr_read(unsigned int device, unsigned int msrRegister, Q_WORD * msrValue)
683#endif
684{
685   if (device < NUM_DEVS) {
686      if (msrDev[device].Present == FOUND)
687	 MSR_READ(msrRegister, msrDev[device].Address, &(msrValue->high),
688		  &(msrValue->low));
689
690      return msrDev[device].Present;
691   }
692   return NOT_KNOWN;
693}
694
695/*--------------------------------------------------------------------
696 * gfx_msr_write
697 *
698 *		Performs a 64-bit write to 'msrRegister' in device 'devID'.
699 *
700 *		Returns:
701 *			FOUND - if no errors were detected and msrValue has been updated.
702 *			NOT_KNOWN	- an error was detected.  msrValue is not updated.
703 *			REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown.  Caller
704 *						should call msrInit() first.  msrValue is not updated.
705 *
706 *		Notes:
707 *      	This function is valid to call after initMSR_API()
708 *
709 *--------------------------------------------------------------------
710 */
711#if GFX_MSR_DYNAMIC
712DEV_STATUS
713redcloud_msr_write(unsigned int device, unsigned int msrRegister,
714		   Q_WORD * msrValue)
715#else
716DEV_STATUS
717gfx_msr_write(unsigned int device, unsigned int msrRegister,
718	      Q_WORD * msrValue)
719#endif
720{
721   if (device < NUM_DEVS) {
722      if (msrDev[device].Present == FOUND)
723	 MSR_WRITE(msrRegister, msrDev[device].Address, &(msrValue->high),
724		   &(msrValue->low));
725
726      return msrDev[device].Present;
727   }
728   return NOT_KNOWN;
729}
730