171d7fec4Smrg/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nsc/gfx/msr_rdcl.c,v 1.1 2002/12/10 15:12:27 alanh Exp $ */
271d7fec4Smrg/*
371d7fec4Smrg * $Workfile: msr_rdcl.c $
471d7fec4Smrg *
571d7fec4Smrg * This file contains MSR access routines for Redcloud.
671d7fec4Smrg *
771d7fec4Smrg * NSC_LIC_ALTERNATIVE_PREAMBLE
871d7fec4Smrg *
971d7fec4Smrg * Revision 1.0
1071d7fec4Smrg *
1171d7fec4Smrg * National Semiconductor Alternative GPL-BSD License
1271d7fec4Smrg *
1371d7fec4Smrg * National Semiconductor Corporation licenses this software
1471d7fec4Smrg * ("Software"):
1571d7fec4Smrg *
1671d7fec4Smrg *      Durango
1771d7fec4Smrg *
1871d7fec4Smrg * under one of the two following licenses, depending on how the
1971d7fec4Smrg * Software is received by the Licensee.
2071d7fec4Smrg *
2171d7fec4Smrg * If this Software is received as part of the Linux Framebuffer or
2271d7fec4Smrg * other GPL licensed software, then the GPL license designated
2371d7fec4Smrg * NSC_LIC_GPL applies to this Software; in all other circumstances
2471d7fec4Smrg * then the BSD-style license designated NSC_LIC_BSD shall apply.
2571d7fec4Smrg *
2671d7fec4Smrg * END_NSC_LIC_ALTERNATIVE_PREAMBLE */
2771d7fec4Smrg
2871d7fec4Smrg/* NSC_LIC_BSD
2971d7fec4Smrg *
3071d7fec4Smrg * National Semiconductor Corporation Open Source License for Durango
3171d7fec4Smrg *
3271d7fec4Smrg * (BSD License with Export Notice)
3371d7fec4Smrg *
3471d7fec4Smrg * Copyright (c) 1999-2001
3571d7fec4Smrg * National Semiconductor Corporation.
3671d7fec4Smrg * All rights reserved.
3771d7fec4Smrg *
3871d7fec4Smrg * Redistribution and use in source and binary forms, with or without
3971d7fec4Smrg * modification, are permitted provided that the following conditions
4071d7fec4Smrg * are met:
4171d7fec4Smrg *
4271d7fec4Smrg *   * Redistributions of source code must retain the above copyright
4371d7fec4Smrg *     notice, this list of conditions and the following disclaimer.
4471d7fec4Smrg *
4571d7fec4Smrg *   * Redistributions in binary form must reproduce the above
4671d7fec4Smrg *     copyright notice, this list of conditions and the following
4771d7fec4Smrg *     disclaimer in the documentation and/or other materials provided
4871d7fec4Smrg *     with the distribution.
4971d7fec4Smrg *
5071d7fec4Smrg *   * Neither the name of the National Semiconductor Corporation nor
5171d7fec4Smrg *     the names of its contributors may be used to endorse or promote
5271d7fec4Smrg *     products derived from this software without specific prior
5371d7fec4Smrg *     written permission.
5471d7fec4Smrg *
5571d7fec4Smrg * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5671d7fec4Smrg * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5771d7fec4Smrg * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
5871d7fec4Smrg * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
5971d7fec4Smrg * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY
6071d7fec4Smrg * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6171d7fec4Smrg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
6271d7fec4Smrg * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
6371d7fec4Smrg * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
6471d7fec4Smrg * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE,
6571d7fec4Smrg * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY
6671d7fec4Smrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
6771d7fec4Smrg * OF SUCH DAMAGE.
6871d7fec4Smrg *
6971d7fec4Smrg * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
7071d7fec4Smrg * YOUR JURISDICTION. It is licensee's responsibility to comply with
7171d7fec4Smrg * any export regulations applicable in licensee's jurisdiction. Under
7271d7fec4Smrg * CURRENT (2001) U.S. export regulations this software
7371d7fec4Smrg * is eligible for export from the U.S. and can be downloaded by or
7471d7fec4Smrg * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed
7571d7fec4Smrg * destinations which include Cuba, Iraq, Libya, North Korea, Iran,
7671d7fec4Smrg * Syria, Sudan, Afghanistan and any other country to which the U.S.
7771d7fec4Smrg * has embargoed goods and services.
7871d7fec4Smrg *
7971d7fec4Smrg * END_NSC_LIC_BSD */
8071d7fec4Smrg
8171d7fec4Smrg/* NSC_LIC_GPL
8271d7fec4Smrg *
8371d7fec4Smrg * National Semiconductor Corporation Gnu General Public License for Durango
8471d7fec4Smrg *
8571d7fec4Smrg * (GPL License with Export Notice)
8671d7fec4Smrg *
8771d7fec4Smrg * Copyright (c) 1999-2001
8871d7fec4Smrg * National Semiconductor Corporation.
8971d7fec4Smrg * All rights reserved.
9071d7fec4Smrg *
9171d7fec4Smrg * Redistribution and use in source and binary forms, with or without
9271d7fec4Smrg * modification, are permitted under the terms of the GNU General
9371d7fec4Smrg * Public License as published by the Free Software Foundation; either
9471d7fec4Smrg * version 2 of the License, or (at your option) any later version
9571d7fec4Smrg *
9671d7fec4Smrg * In addition to the terms of the GNU General Public License, neither
9771d7fec4Smrg * the name of the National Semiconductor Corporation nor the names of
9871d7fec4Smrg * its contributors may be used to endorse or promote products derived
9971d7fec4Smrg * from this software without specific prior written permission.
10071d7fec4Smrg *
10171d7fec4Smrg * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10271d7fec4Smrg * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10371d7fec4Smrg * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
10471d7fec4Smrg * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
10571d7fec4Smrg * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY
10671d7fec4Smrg * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10771d7fec4Smrg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
10871d7fec4Smrg * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
10971d7fec4Smrg * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
11071d7fec4Smrg * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE,
11171d7fec4Smrg * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY
11271d7fec4Smrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
11371d7fec4Smrg * OF SUCH DAMAGE. See the GNU General Public License for more details.
11471d7fec4Smrg *
11571d7fec4Smrg * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
11671d7fec4Smrg * YOUR JURISDICTION. It is licensee's responsibility to comply with
11771d7fec4Smrg * any export regulations applicable in licensee's jurisdiction. Under
11871d7fec4Smrg * CURRENT (2001) U.S. export regulations this software
11971d7fec4Smrg * is eligible for export from the U.S. and can be downloaded by or
12071d7fec4Smrg * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed
12171d7fec4Smrg * destinations which include Cuba, Iraq, Libya, North Korea, Iran,
12271d7fec4Smrg * Syria, Sudan, Afghanistan and any other country to which the U.S.
12371d7fec4Smrg * has embargoed goods and services.
12471d7fec4Smrg *
12571d7fec4Smrg * You should have received a copy of the GNU General Public License
12671d7fec4Smrg * along with this file; if not, write to the Free Software Foundation,
12771d7fec4Smrg * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
12871d7fec4Smrg *
12971d7fec4Smrg * END_NSC_LIC_GPL */
13071d7fec4Smrg
13171d7fec4Smrgint redcloud_msr_init(void);
13271d7fec4SmrgDEV_STATUS redcloud_id_msr_device(MSR * pDev, unsigned long address);
13371d7fec4SmrgDEV_STATUS redcloud_get_msr_dev_address(unsigned int device,
13471d7fec4Smrg					unsigned long *address);
13571d7fec4SmrgDEV_STATUS redcloud_get_glink_id_at_address(unsigned int *device,
13671d7fec4Smrg					    unsigned long address);
13771d7fec4SmrgDEV_STATUS redcloud_msr_read(unsigned int device, unsigned int msrRegister,
13871d7fec4Smrg			     Q_WORD * msrValue);
13971d7fec4SmrgDEV_STATUS redcloud_msr_write(unsigned int device, unsigned int msrRegister,
14071d7fec4Smrg			      Q_WORD * msrValue);
14171d7fec4Smrg
14271d7fec4Smrgvoid redcloud_build_mbus_tree(void);	/* private routine definition */
14371d7fec4Smrgint redcloud_init_msr_devices(MSR aDev[], unsigned int array_size);	/* private routine definition */
14471d7fec4SmrgDEV_STATUS redcloud_find_msr_device(MSR * pDev);	/* private routine definition */
14571d7fec4Smrg
14671d7fec4Smrg/* REDCLOUD MSR BITMASKS */
14771d7fec4Smrg
14871d7fec4Smrg#define MBD_MSR_CAP			0x2000
14971d7fec4Smrg#define MSR_CAP_ID_MASK		0xFF000
15071d7fec4Smrg#define MSR_CAP_ID_SHIFT  	12
15171d7fec4Smrg#define MSR_CAP_REV_MASK    0x0F
15271d7fec4Smrg#define MBIU_CAP			0x86
15371d7fec4Smrg#define NUM_PORTS_MASK		0x00380000
15471d7fec4Smrg#define NUM_PORTS_SHIFT  	19
15571d7fec4Smrg#define MBIU_WHOAMI			0x8B
15671d7fec4Smrg#define WHOAMI_MASK			0x07
15771d7fec4Smrg
15871d7fec4Smrg/* REDCLOUD and CS5535 MSR DEVICES */
15971d7fec4Smrg
16071d7fec4SmrgMSR msrDev[] = {
16171d7fec4Smrg   {FOUND, RC_CC_MBIU, RC_MB0_MBIU0},
16271d7fec4Smrg   {FOUND, RC_CC_MBIU, RC_MB0_MBIU1},
16371d7fec4Smrg   {NOT_KNOWN, RC_CC_MCP, FAKE_ADDRESS},
16471d7fec4Smrg   {NOT_KNOWN, RC_CC_MPCI, FAKE_ADDRESS},
16571d7fec4Smrg   {NOT_KNOWN, RC_CC_MC, FAKE_ADDRESS},
16671d7fec4Smrg   {NOT_KNOWN, RC_CC_GP, FAKE_ADDRESS},
16771d7fec4Smrg   {NOT_KNOWN, RC_CC_VG, FAKE_ADDRESS},
16871d7fec4Smrg   {NOT_KNOWN, RC_CC_DF, FAKE_ADDRESS},
16971d7fec4Smrg   {NOT_KNOWN, RC_CC_FG, FAKE_ADDRESS},
17071d7fec4Smrg   {FOUND, RC_CC_VA, RC_MB0_CPU},
17171d7fec4Smrg   {FOUND, CP_CC_MBIU, CP_MB0_MBIU0},
17271d7fec4Smrg   {NOT_KNOWN, CP_CC_MPCI, FAKE_ADDRESS},
17371d7fec4Smrg   {NOT_KNOWN, CP_CC_USB2, FAKE_ADDRESS},
17471d7fec4Smrg   {NOT_KNOWN, CP_CC_ATAC, FAKE_ADDRESS},
17571d7fec4Smrg   {NOT_KNOWN, CP_CC_MDD, FAKE_ADDRESS},
17671d7fec4Smrg   {NOT_KNOWN, CP_CC_ACC, FAKE_ADDRESS},
17771d7fec4Smrg   {NOT_KNOWN, CP_CC_USB1, FAKE_ADDRESS},
17871d7fec4Smrg   {NOT_KNOWN, CP_CC_MCP, FAKE_ADDRESS},
17971d7fec4Smrg};
18071d7fec4Smrg
18171d7fec4Smrg#define NUM_DEVS sizeof(msrDev) / sizeof(struct msr)
18271d7fec4Smrg
18371d7fec4Smrg/* CAPISTRANO DEVICE INDEX LIMITS */
18471d7fec4Smrg/* These defines represent the start and stop indexes into the device array  */
18571d7fec4Smrg/* for all Capistrano devices.  These should be updated whenever a device is */
18671d7fec4Smrg/* added or removed to the Capistrano list.                                  */
18771d7fec4Smrg
18871d7fec4Smrg#define CP_INDEX_START CP_ID_MBIU
18971d7fec4Smrg#define CP_INDEX_STOP  CP_ID_MCP
19071d7fec4Smrg
19171d7fec4Smrg/* GLOBAL MBUS CACHE STRUCTURES */
19271d7fec4Smrg/* These structures contain a "cached" copy of the MBUS topology */
19371d7fec4Smrg/* for easy future lookup.                                       */
19471d7fec4Smrg
19571d7fec4SmrgMBUS_NODE MBIU0[8], MBIU1[8], MBIU2[8];
19671d7fec4Smrg
19771d7fec4Smrg/* REGISTER MACROS */
19871d7fec4Smrg
19971d7fec4Smrg#define GET_DEVICE_ID( CAPABILITIES_HIGH, CAPABILITIES_LOW ) \
20071d7fec4Smrg					 ((unsigned int)(( (CAPABILITIES_LOW) & MSR_CAP_ID_MASK ) >> MSR_CAP_ID_SHIFT ))
20171d7fec4Smrg
20271d7fec4Smrg#define GET_NUM_PORTS( MBIU_CAP_HIGH, MBIU_CAP_LOW ) (((MBIU_CAP_HIGH) & NUM_PORTS_MASK ) >> NUM_PORTS_SHIFT)
20371d7fec4Smrg
20471d7fec4Smrg/*-----------------------------------------------------------------------------
20571d7fec4Smrg * gfx_msr_init
20671d7fec4Smrg *
20771d7fec4Smrg * This routine initializes the base addresses of all known MBUS devices.
20871d7fec4Smrg *-----------------------------------------------------------------------------
20971d7fec4Smrg */
21071d7fec4Smrg#if GFX_MSR_DYNAMIC
21171d7fec4Smrgint
21271d7fec4Smrgredcloud_msr_init(void)
21371d7fec4Smrg#else
21471d7fec4Smrgint
21571d7fec4Smrggfx_msr_init(void)
21671d7fec4Smrg#endif
21771d7fec4Smrg{
21871d7fec4Smrg   Q_WORD msrValue;
21971d7fec4Smrg   int return_value = 1;
22071d7fec4Smrg
22171d7fec4Smrg   /* CHECK FOR VALID MBUS CONFIGURATION */
22271d7fec4Smrg   /* The CPU and the two MBIUs are assumed to be at known static addresses, so */
22371d7fec4Smrg   /* we will check the device IDs at these addresses as proof of a valid mbus  */
22471d7fec4Smrg   /* configuration.                                                            */
22571d7fec4Smrg
22671d7fec4Smrg   MSR_READ(MBD_MSR_CAP, RC_MB0_CPU, &(msrValue.high), &(msrValue.low));
22771d7fec4Smrg   if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_VA)
22871d7fec4Smrg      return_value = 0;
22971d7fec4Smrg
23071d7fec4Smrg   MSR_READ(MBD_MSR_CAP, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
23171d7fec4Smrg   if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_MBIU)
23271d7fec4Smrg      return_value = 0;
23371d7fec4Smrg
23471d7fec4Smrg   MSR_READ(MBD_MSR_CAP, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low));
23571d7fec4Smrg   if (GET_DEVICE_ID(msrValue.high, msrValue.low) != RC_CC_MBIU)
23671d7fec4Smrg      return_value = 0;
23771d7fec4Smrg
23871d7fec4Smrg   /* ENUMERATE VALID BUS */
23971d7fec4Smrg   /* If all static devices were identified, continue with the enumeration */
24071d7fec4Smrg
24171d7fec4Smrg   if (return_value) {
24271d7fec4Smrg      /* OPTIMIZATION */
24371d7fec4Smrg      /* Build a local copy of the MBUS topology.  This allows us to  */
24471d7fec4Smrg      /* quickly search the entire MBUS for a given device ID without */
24571d7fec4Smrg      /* repeated MSR accesses.                                       */
24671d7fec4Smrg
24771d7fec4Smrg      redcloud_build_mbus_tree();
24871d7fec4Smrg
24971d7fec4Smrg      /* INITIALIZE MSR DEVICES */
25071d7fec4Smrg
25171d7fec4Smrg      return_value = redcloud_init_msr_devices(msrDev, NUM_DEVS);
25271d7fec4Smrg
25371d7fec4Smrg   }
25471d7fec4Smrg
25571d7fec4Smrg   return return_value;
25671d7fec4Smrg
25771d7fec4Smrg}
25871d7fec4Smrg
25971d7fec4Smrg/*--------------------------------------------------------------------------
26071d7fec4Smrg * void	redcloud_build_mbus_tree() (PRIVATE ROUTINE - NOT PART OF DURANGO API)
26171d7fec4Smrg *
26271d7fec4Smrg * This routine walks through the MBUS and records the address value and
26371d7fec4Smrg * device ID found at each node.  If a node (aka port) is not populated,
26471d7fec4Smrg * that node returns '0'.  The deviceID for that node is set to '0'
26571d7fec4Smrg * (NOT_POPULATED) to reflect this. If the node being queried points back to
26671d7fec4Smrg * Vail or MBIU0, the deviceID for that node is set to 'REFLECTIVE'.  Reflective
26771d7fec4Smrg * nodes are nodes that forward the given MBUS address BACK to the initiator.
26871d7fec4Smrg *-----------------------------------------------------------------------------
26971d7fec4Smrg */
27071d7fec4Smrgvoid
27171d7fec4Smrgredcloud_build_mbus_tree(void)
27271d7fec4Smrg{
27371d7fec4Smrg   unsigned long mbiu_port_count, reflective;
27471d7fec4Smrg   unsigned long port;
27571d7fec4Smrg   Q_WORD msrValue;
27671d7fec4Smrg
27771d7fec4Smrg   /*                  */
27871d7fec4Smrg   /* ENUMERATE MBIU0  */
27971d7fec4Smrg   /*                  */
28071d7fec4Smrg
28171d7fec4Smrg   /* COUNT MBIU PORTS */
28271d7fec4Smrg
28371d7fec4Smrg   MSR_READ(MBIU_CAP, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
28471d7fec4Smrg   mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low);
28571d7fec4Smrg
28671d7fec4Smrg   /* FIND REFLECTIVE PORT */
28771d7fec4Smrg   /* Query the MBIU for the port through which we are communicating. */
28871d7fec4Smrg   /* We will avoid accesses to this port to avoid a self-reference.  */
28971d7fec4Smrg
29071d7fec4Smrg   MSR_READ(MBIU_WHOAMI, RC_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
29171d7fec4Smrg   reflective = msrValue.low & WHOAMI_MASK;
29271d7fec4Smrg
29371d7fec4Smrg   /* ENUMERATE ALL PORTS */
29471d7fec4Smrg   /* For every possible port, set the MBIU.deviceId to something. */
29571d7fec4Smrg
29671d7fec4Smrg   for (port = 0; port < 8; port++) {
29771d7fec4Smrg      /* FILL IN CLAIMED FIELD */
29871d7fec4Smrg      /* All MBIU ports can only be assigned to one device from the */
29971d7fec4Smrg      /* Durango table                                              */
30071d7fec4Smrg
30171d7fec4Smrg      MBIU0[port].claimed = 0;
30271d7fec4Smrg
30371d7fec4Smrg      /* MBIU0 PORT NUMBERS ARE IN ADDRESS BITS 31:29 */
30471d7fec4Smrg
30571d7fec4Smrg      MBIU0[port].address = port << 29;
30671d7fec4Smrg
30771d7fec4Smrg      /* SPECIAL CASE FOR MBIU0 */
30871d7fec4Smrg      /* MBIU0 port 0 is a special case, as it points back to MBIU0.  MBIU0 */
30971d7fec4Smrg      /* responds at address 0x40000xxx, which does not equal 0 << 29.      */
31071d7fec4Smrg
31171d7fec4Smrg      if (port == 0)
31271d7fec4Smrg	 MBIU0[port].deviceId = RC_CC_MBIU;
31371d7fec4Smrg      else if (port == reflective)
31471d7fec4Smrg	 MBIU0[port].deviceId = REFLECTIVE;
31571d7fec4Smrg      else if (port > mbiu_port_count)
31671d7fec4Smrg	 MBIU0[port].deviceId = NOT_POPULATED;
31771d7fec4Smrg      else {
31871d7fec4Smrg	 MSR_READ(MBD_MSR_CAP, MBIU0[port].address, &(msrValue.high),
31971d7fec4Smrg		  &(msrValue.low));
32071d7fec4Smrg	 MBIU0[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low);
32171d7fec4Smrg      }
32271d7fec4Smrg   }
32371d7fec4Smrg
32471d7fec4Smrg   /*                  */
32571d7fec4Smrg   /* ENUMERATE MBIU1  */
32671d7fec4Smrg   /*                  */
32771d7fec4Smrg
32871d7fec4Smrg   /* COUNT MBIU PORTS */
32971d7fec4Smrg
33071d7fec4Smrg   MSR_READ(MBIU_CAP, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low));
33171d7fec4Smrg   mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low);
33271d7fec4Smrg
33371d7fec4Smrg   /* FIND REFLECTIVE PORT */
33471d7fec4Smrg   /* Query the MBIU for the port through which we are communicating. */
33571d7fec4Smrg   /* We will avoid accesses to this port to avoid a self-reference.  */
33671d7fec4Smrg
33771d7fec4Smrg   MSR_READ(MBIU_WHOAMI, RC_MB0_MBIU1, &(msrValue.high), &(msrValue.low));
33871d7fec4Smrg   reflective = msrValue.low & WHOAMI_MASK;
33971d7fec4Smrg
34071d7fec4Smrg   /* ENUMERATE ALL PORTS */
34171d7fec4Smrg   /* For every possible port, set the MBIU.deviceId to something. */
34271d7fec4Smrg
34371d7fec4Smrg   for (port = 0; port < 8; port++) {
34471d7fec4Smrg      /* FILL IN CLAIMED FIELD */
34571d7fec4Smrg      /* All MBIU ports can only be assigned to one device from the */
34671d7fec4Smrg      /* Durango table                                              */
34771d7fec4Smrg
34871d7fec4Smrg      MBIU1[port].claimed = 0;
34971d7fec4Smrg
35071d7fec4Smrg      /* MBIU1 PORT NUMBERS ARE IN 28:26 AND 31:29 = 010B */
35171d7fec4Smrg
35271d7fec4Smrg      MBIU1[port].address = (0x02l << 29) + (port << 26);
35371d7fec4Smrg
35471d7fec4Smrg      if (port == reflective)
35571d7fec4Smrg	 MBIU1[port].deviceId = REFLECTIVE;
35671d7fec4Smrg      else if (port > mbiu_port_count)
35771d7fec4Smrg	 MBIU1[port].deviceId = NOT_POPULATED;
35871d7fec4Smrg      else {
35971d7fec4Smrg	 MSR_READ(MBD_MSR_CAP, MBIU1[port].address, &(msrValue.high),
36071d7fec4Smrg		  &(msrValue.low));
36171d7fec4Smrg	 MBIU1[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low);
36271d7fec4Smrg      }
36371d7fec4Smrg   }
36471d7fec4Smrg
36571d7fec4Smrg   /*                          */
36671d7fec4Smrg   /* ENUMERATE MBIU2 (CS5535) */
36771d7fec4Smrg   /*  (if present)            */
36871d7fec4Smrg
36971d7fec4Smrg   MSR_READ(MBD_MSR_CAP, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
37071d7fec4Smrg   if (GET_DEVICE_ID(msrValue.high, msrValue.low) == CP_CC_MBIU) {
37171d7fec4Smrg      /* COUNT MBIU PORTS */
37271d7fec4Smrg
37371d7fec4Smrg      MSR_READ(MBIU_CAP, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
37471d7fec4Smrg      mbiu_port_count = GET_NUM_PORTS(msrValue.high, msrValue.low);
37571d7fec4Smrg
37671d7fec4Smrg      /* FIND REFLECTIVE PORT */
37771d7fec4Smrg      /* Query the MBIU for the port through which we are communicating. */
37871d7fec4Smrg      /* We will avoid accesses to this port to avoid a self-reference.  */
37971d7fec4Smrg
38071d7fec4Smrg      MSR_READ(MBIU_WHOAMI, CP_MB0_MBIU0, &(msrValue.high), &(msrValue.low));
38171d7fec4Smrg      reflective = msrValue.low & WHOAMI_MASK;
38271d7fec4Smrg
38371d7fec4Smrg      /* ENUMERATE ALL PORTS */
38471d7fec4Smrg      /* For every possible port, set the MBIU.deviceId to something. */
38571d7fec4Smrg
38671d7fec4Smrg      for (port = 0; port < 8; port++) {
38771d7fec4Smrg	 /* FILL IN CLAIMED FIELD */
38871d7fec4Smrg	 /* All MBIU ports can only be assigned to one device from the */
38971d7fec4Smrg	 /* Durango table                                              */
39071d7fec4Smrg
39171d7fec4Smrg	 MBIU2[port].claimed = 0;
39271d7fec4Smrg
39371d7fec4Smrg	 /* MBIU2 PORT NUMBERS ARE IN 22:20 AND 31:23 = 010100010B */
39471d7fec4Smrg
39571d7fec4Smrg	 MBIU2[port].address =
39671d7fec4Smrg	       (0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20);
39771d7fec4Smrg
39871d7fec4Smrg	 if (port == reflective)
39971d7fec4Smrg	    MBIU2[port].deviceId = REFLECTIVE;
40071d7fec4Smrg	 else if (port > mbiu_port_count)
40171d7fec4Smrg	    MBIU2[port].deviceId = NOT_POPULATED;
40271d7fec4Smrg	 else {
40371d7fec4Smrg	    MSR_READ(MBD_MSR_CAP, MBIU2[port].address, &(msrValue.high),
40471d7fec4Smrg		     &(msrValue.low));
40571d7fec4Smrg	    MBIU2[port].deviceId = GET_DEVICE_ID(msrValue.high, msrValue.low);
40671d7fec4Smrg	 }
40771d7fec4Smrg      }
40871d7fec4Smrg   } else {
40971d7fec4Smrg      /* NO 5535                                                  */
41071d7fec4Smrg      /* If the CS5535 is not installed, fill in the cached table */
41171d7fec4Smrg      /* with the 'NOT_INSTALLED' flag.  Also, fill in the device */
41271d7fec4Smrg      /* status from NOT_KNOWN to REQ_NOT_INSTALLED.              */
41371d7fec4Smrg
41471d7fec4Smrg      for (port = 0; port < 8; port++) {
41571d7fec4Smrg	 MBIU2[port].claimed = 0;
41671d7fec4Smrg	 MBIU2[port].deviceId = NOT_INSTALLED;
41771d7fec4Smrg	 MBIU2[port].address =
41871d7fec4Smrg	       (0x02l << 29) + (0x04l << 26) + (0x02l << 23) + (port << 20);
41971d7fec4Smrg      }
42071d7fec4Smrg      for (port = CP_INDEX_START; port <= CP_INDEX_STOP; port++) {
42171d7fec4Smrg	 msrDev[port].Present = REQ_NOT_INSTALLED;
42271d7fec4Smrg      }
42371d7fec4Smrg   }
42471d7fec4Smrg}
42571d7fec4Smrg
42671d7fec4Smrg/*------------------------------------------------------------------
42771d7fec4Smrg * redcloud_init_msr_devices (PRIVATE ROUTINE - NOT PART OF DURANGO API)
42871d7fec4Smrg
42971d7fec4Smrg * Handles the details of finding each possible device on the MBUS.
43071d7fec4Smrg * If a given device is not found, its structure is left uninitialized.
43171d7fec4Smrg * If a given device is found, its structure is updated.
43271d7fec4Smrg *
43371d7fec4Smrg * This init routine only checks for devices in aDev[].
43471d7fec4Smrg *
43571d7fec4Smrg *  Passed:
43671d7fec4Smrg *		aDev - is a pointer to the array of MBUS devices.
43771d7fec4Smrg *		arraySize - number of elements in aDev.
43871d7fec4Smrg *
43971d7fec4Smrg *	Returns:
44071d7fec4Smrg *		1 - If, for every device, its address was found.
44171d7fec4Smrg *		0 - If, for any device, an error was encountered.
44271d7fec4Smrg *------------------------------------------------------------------
44371d7fec4Smrg */
44471d7fec4Smrgint
44571d7fec4Smrgredcloud_init_msr_devices(MSR aDev[], unsigned int array_size)
44671d7fec4Smrg{
44771d7fec4Smrg   unsigned int i, issues = 0;
44871d7fec4Smrg
44971d7fec4Smrg   /* TRY TO FIND EACH ITEM IN THE ARRAY */
45071d7fec4Smrg
45171d7fec4Smrg   for (i = 0; i < array_size; i++) {
45271d7fec4Smrg      /* IGNORE DEVICES THAT ARE ALREADY FOUND                */
45371d7fec4Smrg      /* The addresses for "found" devices are already known. */
45471d7fec4Smrg
45571d7fec4Smrg      if (aDev[i].Present == FOUND || aDev[i].Present == REQ_NOT_INSTALLED)
45671d7fec4Smrg	 continue;
45771d7fec4Smrg
45871d7fec4Smrg      /* TRY TO FIND THE DEVICE ON THE MBUS */
45971d7fec4Smrg
46071d7fec4Smrg      aDev[i].Present = redcloud_find_msr_device(&aDev[i]);
46171d7fec4Smrg
46271d7fec4Smrg      /* INCREMENT ERROR COUNT IF DEVICE NOT FOUND */
46371d7fec4Smrg
46471d7fec4Smrg      if (aDev[i].Present != FOUND)
46571d7fec4Smrg	 issues++;
46671d7fec4Smrg   }
46771d7fec4Smrg
46871d7fec4Smrg   return (issues == 0);
46971d7fec4Smrg}
47071d7fec4Smrg
47171d7fec4Smrg/*------------------------------------------------------------------
47271d7fec4Smrg *  redcloud_find_msr_device (PRIVATE ROUTINE - NOT PART OF DURANGO API)
47371d7fec4Smrg *
47471d7fec4Smrg *  Passed:
47571d7fec4Smrg *	    pDev - is a pointer to one element in the array of MBUS devices
47671d7fec4Smrg *
47771d7fec4Smrg *  Returns:
47871d7fec4Smrg *	    FOUND - Device was found and pDev->Address has been updated.
47971d7fec4Smrg *
48071d7fec4Smrg *		REQ_NOT_FOUND - Device was not found and pDev->Address has not
48171d7fec4Smrg *						been updated.
48271d7fec4Smrg *
48371d7fec4Smrg *------------------------------------------------------------------
48471d7fec4Smrg*/
48571d7fec4SmrgDEV_STATUS
48671d7fec4Smrgredcloud_find_msr_device(MSR * pDev)
48771d7fec4Smrg{
48871d7fec4Smrg   unsigned int i;
48971d7fec4Smrg
49071d7fec4Smrg   /* SEARCH DURANGO'S CACHED MBUS TOPOLOGY */
49171d7fec4Smrg   /* This gets a little tricky.  As the only identifier we have for each   */
49271d7fec4Smrg   /* device is the device ID and we have multiple devices of the same type */
49371d7fec4Smrg   /* MCP, MPCI, USB, etc. we need to make some assumptions based on table  */
49471d7fec4Smrg   /* order.  These are as follows:                                         */
49571d7fec4Smrg   /* 1. All Redcloud nodes are searched first, as we assume that they      */
49671d7fec4Smrg   /*    are first in the table.                                            */
49771d7fec4Smrg   /* 2. If two devices have the same device ID and are found on the same   */
49871d7fec4Smrg   /*    device (GX2, CS5535, etc.) we assume that they are listed such     */
49971d7fec4Smrg   /*    that the first device in the table with this device ID has a lower */
50071d7fec4Smrg   /*    port address.                                                      */
50171d7fec4Smrg   /* 3. After a device ID has been matched, the port is marked as          */
50271d7fec4Smrg   /*    'claimed', such that future enumerations continue searching the    */
50371d7fec4Smrg   /*    GeodeLink topology.                                                */
50471d7fec4Smrg
50571d7fec4Smrg   /* SEARCH MBIU0 */
50671d7fec4Smrg
50771d7fec4Smrg   for (i = 0; i < 8; i++) {
50871d7fec4Smrg      if (MBIU0[i].deviceId == pDev->Id && !(MBIU0[i].claimed)) {
50971d7fec4Smrg	 MBIU0[i].claimed = 1;
51071d7fec4Smrg	 pDev->Address = MBIU0[i].address;
51171d7fec4Smrg	 return FOUND;
51271d7fec4Smrg      }
51371d7fec4Smrg   }
51471d7fec4Smrg
51571d7fec4Smrg   /* SEARCH MBIU1 */
51671d7fec4Smrg
51771d7fec4Smrg   for (i = 0; i < 8; i++) {
51871d7fec4Smrg      if (MBIU1[i].deviceId == pDev->Id && !(MBIU1[i].claimed)) {
51971d7fec4Smrg	 MBIU1[i].claimed = 1;
52071d7fec4Smrg	 pDev->Address = MBIU1[i].address;
52171d7fec4Smrg	 return FOUND;
52271d7fec4Smrg      }
52371d7fec4Smrg   }
52471d7fec4Smrg
52571d7fec4Smrg   /* SEARCH MBIU2 */
52671d7fec4Smrg
52771d7fec4Smrg   for (i = 0; i < 8; i++) {
52871d7fec4Smrg      if (MBIU2[i].deviceId == pDev->Id && !(MBIU2[i].claimed)) {
52971d7fec4Smrg	 MBIU2[i].claimed = 1;
53071d7fec4Smrg	 pDev->Address = MBIU2[i].address;
53171d7fec4Smrg	 return FOUND;
53271d7fec4Smrg      }
53371d7fec4Smrg   }
53471d7fec4Smrg
53571d7fec4Smrg   return REQ_NOT_FOUND;
53671d7fec4Smrg}
53771d7fec4Smrg
53871d7fec4Smrg/*--------------------------------------------------------------------
53971d7fec4Smrg * gfx_id_msr_device
54071d7fec4Smrg *
54171d7fec4Smrg *	This routine handles reading the capabilities MSR register (typically 0x2000)
54271d7fec4Smrg *	and checking if the 'id' field matchs  pDev.Id.  This routine is
54371d7fec4Smrg *  used by applications/drivers that need to extend the list of known
54471d7fec4Smrg *  MBUS devices beyond those known by Durango.
54571d7fec4Smrg *
54671d7fec4Smrg *		Passed:
54771d7fec4Smrg *			pDev - Pointer to MSR structure containing the device's ID.
54871d7fec4Smrg *		    address - device address.
54971d7fec4Smrg *
55071d7fec4Smrg *		Returns:
55171d7fec4Smrg *			FOUND - The IDs do match.
55271d7fec4Smrg *			REQ_NOT_FOUND - There was not a match.
55371d7fec4Smrg *
55471d7fec4Smrg *--------------------------------------------------------------------
55571d7fec4Smrg */
55671d7fec4Smrg#if GFX_MSR_DYNAMIC
55771d7fec4SmrgDEV_STATUS
55871d7fec4Smrgredcloud_id_msr_device(MSR * pDev, unsigned long address)
55971d7fec4Smrg#else
56071d7fec4SmrgDEV_STATUS
56171d7fec4Smrggfx_id_msr_device(MSR * pDev, unsigned long address)
56271d7fec4Smrg#endif
56371d7fec4Smrg{
56471d7fec4Smrg   Q_WORD msrValue;
56571d7fec4Smrg
56671d7fec4Smrg   MSR_READ(MBD_MSR_CAP, address, &(msrValue.high), &(msrValue.low));
56771d7fec4Smrg
56871d7fec4Smrg   if (GET_DEVICE_ID(msrValue.high, msrValue.low) == pDev->Id)
56971d7fec4Smrg      return FOUND;
57071d7fec4Smrg   else
57171d7fec4Smrg      return REQ_NOT_FOUND;
57271d7fec4Smrg}
57371d7fec4Smrg
57471d7fec4Smrg/*--------------------------------------------------------------------
57571d7fec4Smrg * gfx_get_msr_dev_address
57671d7fec4Smrg *
57771d7fec4Smrg * This function returns the 32-bit address of the requested device.
57871d7fec4Smrg * The device must be a known MBUS device.  (It must be in Durango's
57971d7fec4Smrg * device table.)  DEV_STATUS should be checked to verify that the address
58071d7fec4Smrg * was updated.
58171d7fec4Smrg *
58271d7fec4Smrg *
58371d7fec4Smrg * Passed:
58471d7fec4Smrg *     device - device index of the device in question.
58571d7fec4Smrg *	   *address - ptr to location where address should be stored.
58671d7fec4Smrg *
58771d7fec4Smrg * Returns:
58871d7fec4Smrg *	   DEV_STATUS of device in question.  (NOT_KNOWN if device is out of range.)
58971d7fec4Smrg *     *address - updated if 'device' is within range
59071d7fec4Smrg *
59171d7fec4Smrg *	Notes:
59271d7fec4Smrg *     This function should only be called after gfx_msr_init
59371d7fec4Smrg *
59471d7fec4Smrg *--------------------------------------------------------------------
59571d7fec4Smrg */
59671d7fec4Smrg#if GFX_MSR_DYNAMIC
59771d7fec4SmrgDEV_STATUS
59871d7fec4Smrgredcloud_get_msr_dev_address(unsigned int device, unsigned long *address)
59971d7fec4Smrg#else
60071d7fec4SmrgDEV_STATUS
60171d7fec4Smrggfx_get_msr_dev_address(unsigned int device, unsigned long *address)
60271d7fec4Smrg#endif
60371d7fec4Smrg{
60471d7fec4Smrg   if (device < NUM_DEVS) {
60571d7fec4Smrg      if (msrDev[device].Present == FOUND)
60671d7fec4Smrg	 *address = msrDev[device].Address;
60771d7fec4Smrg
60871d7fec4Smrg      return msrDev[device].Present;
60971d7fec4Smrg   }
61071d7fec4Smrg   return NOT_KNOWN;
61171d7fec4Smrg
61271d7fec4Smrg}
61371d7fec4Smrg
61471d7fec4Smrg/*--------------------------------------------------------------------
61571d7fec4Smrg *  gfx_get_glink_id_at_address
61671d7fec4Smrg *
61771d7fec4Smrg *	This function returns the 16-bit deviceId at the requested address.
61871d7fec4Smrg *  DEV_STATUS should be checked to make sure that device was updated.
61971d7fec4Smrg *
62071d7fec4Smrg *	Passed:
62171d7fec4Smrg *	    device - ptr to location where device ID should be stored.
62271d7fec4Smrg *		address - address of desired device ID.
62371d7fec4Smrg *
62471d7fec4Smrg *  Returns:
62571d7fec4Smrg *	    FOUND if address is a valid address, NOT_KNOWN if address cannot be found
62671d7fec4Smrg *      on the mbus.
62771d7fec4Smrg *      *device - updated with device Id info.
62871d7fec4Smrg *
62971d7fec4Smrg *	Notes:
63071d7fec4Smrg *      This function should be called after gfx_msr_init
63171d7fec4Smrg *
63271d7fec4Smrg *--------------------------------------------------------------------
63371d7fec4Smrg */
63471d7fec4Smrg#if GFX_MSR_DYNAMIC
63571d7fec4SmrgDEV_STATUS
63671d7fec4Smrgredcloud_get_glink_id_at_address(unsigned int *device, unsigned long address)
63771d7fec4Smrg#else
63871d7fec4SmrgDEV_STATUS
63971d7fec4Smrggfx_get_glink_id_at_address(unsigned int *device, unsigned long address)
64071d7fec4Smrg#endif
64171d7fec4Smrg{
64271d7fec4Smrg   int port;
64371d7fec4Smrg
64471d7fec4Smrg   for (port = 0; port < 8; port++) {
64571d7fec4Smrg      if (MBIU0[port].address == address) {
64671d7fec4Smrg	 *device = MBIU0[port].deviceId;
64771d7fec4Smrg	 return FOUND;
64871d7fec4Smrg      } else if (MBIU1[port].address == address) {
64971d7fec4Smrg	 *device = MBIU1[port].deviceId;
65071d7fec4Smrg	 return FOUND;
65171d7fec4Smrg      } else if (MBIU2[port].address == address) {
65271d7fec4Smrg	 *device = MBIU2[port].deviceId;
65371d7fec4Smrg	 return FOUND;
65471d7fec4Smrg      }
65571d7fec4Smrg   }
65671d7fec4Smrg
65771d7fec4Smrg   return NOT_KNOWN;
65871d7fec4Smrg
65971d7fec4Smrg}
66071d7fec4Smrg
66171d7fec4Smrg/*--------------------------------------------------------------------
66271d7fec4Smrg * gfx_msr_read
66371d7fec4Smrg *
66471d7fec4Smrg * Performs a 64-bit read from 'msrRegister' in device 'device'.  'device' is
66571d7fec4Smrg * an index into Durango's table of known MBUS devices.
66671d7fec4Smrg *
66771d7fec4Smrg * Returns:
66871d7fec4Smrg *     FOUND - if no errors were detected and msrValue has been updated.
66971d7fec4Smrg *	   NOT_KNOWN	- an error was detected.  msrValue is not updated.
67071d7fec4Smrg *	   REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown.  Caller
67171d7fec4Smrg *						should call msrInit() first.  msrValue is not updated.
67271d7fec4Smrg *	   Notes:
67371d7fec4Smrg *         This function should be called after gfx_msr_init
67471d7fec4Smrg *--------------------------------------------------------------------
67571d7fec4Smrg */
67671d7fec4Smrg#if GFX_MSR_DYNAMIC
67771d7fec4SmrgDEV_STATUS
67871d7fec4Smrgredcloud_msr_read(unsigned int device, unsigned int msrRegister,
67971d7fec4Smrg		  Q_WORD * msrValue)
68071d7fec4Smrg#else
68171d7fec4SmrgDEV_STATUS
68271d7fec4Smrggfx_msr_read(unsigned int device, unsigned int msrRegister, Q_WORD * msrValue)
68371d7fec4Smrg#endif
68471d7fec4Smrg{
68571d7fec4Smrg   if (device < NUM_DEVS) {
68671d7fec4Smrg      if (msrDev[device].Present == FOUND)
68771d7fec4Smrg	 MSR_READ(msrRegister, msrDev[device].Address, &(msrValue->high),
68871d7fec4Smrg		  &(msrValue->low));
68971d7fec4Smrg
69071d7fec4Smrg      return msrDev[device].Present;
69171d7fec4Smrg   }
69271d7fec4Smrg   return NOT_KNOWN;
69371d7fec4Smrg}
69471d7fec4Smrg
69571d7fec4Smrg/*--------------------------------------------------------------------
69671d7fec4Smrg * gfx_msr_write
69771d7fec4Smrg *
69871d7fec4Smrg *		Performs a 64-bit write to 'msrRegister' in device 'devID'.
69971d7fec4Smrg *
70071d7fec4Smrg *		Returns:
70171d7fec4Smrg *			FOUND - if no errors were detected and msrValue has been updated.
70271d7fec4Smrg *			NOT_KNOWN	- an error was detected.  msrValue is not updated.
70371d7fec4Smrg *			REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown.  Caller
70471d7fec4Smrg *						should call msrInit() first.  msrValue is not updated.
70571d7fec4Smrg *
70671d7fec4Smrg *		Notes:
70771d7fec4Smrg *      	This function is valid to call after initMSR_API()
70871d7fec4Smrg *
70971d7fec4Smrg *--------------------------------------------------------------------
71071d7fec4Smrg */
71171d7fec4Smrg#if GFX_MSR_DYNAMIC
71271d7fec4SmrgDEV_STATUS
71371d7fec4Smrgredcloud_msr_write(unsigned int device, unsigned int msrRegister,
71471d7fec4Smrg		   Q_WORD * msrValue)
71571d7fec4Smrg#else
71671d7fec4SmrgDEV_STATUS
71771d7fec4Smrggfx_msr_write(unsigned int device, unsigned int msrRegister,
71871d7fec4Smrg	      Q_WORD * msrValue)
71971d7fec4Smrg#endif
72071d7fec4Smrg{
72171d7fec4Smrg   if (device < NUM_DEVS) {
72271d7fec4Smrg      if (msrDev[device].Present == FOUND)
72371d7fec4Smrg	 MSR_WRITE(msrRegister, msrDev[device].Address, &(msrValue->high),
72471d7fec4Smrg		   &(msrValue->low));
72571d7fec4Smrg
72671d7fec4Smrg      return msrDev[device].Present;
72771d7fec4Smrg   }
72871d7fec4Smrg   return NOT_KNOWN;
72971d7fec4Smrg}
730