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