#ident "kit/NEC41XX/sbdfreq.c: Copyright (c) MIPS Technologies, Inc. All rights reserved."

/*
 * Copyright (c) 1998-2003 MIPS Technologies, Inc.
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *      * Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above
 *      copyright
 *        notice, this list of conditions and the following disclaimer
 *        in the documentation and/or other materials provided with
 *        the distribution.
 *      * Neither the name of MIPS Technologies Inc. nor the names of its
 *        contributors may be used to endorse or promote products derived
 *        from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* 
 * NEC41XX/sbdfreq.c: CPU frequency determination for NEC Vr41xx board
 */


#include <stddef.h>
#include <time.h>
#include <errno.h>
#include <mips/cpu.h>
#include <mips/prid.h>

#include "kit_impl.h"
#include "sbd.h"


/* 
 * The Vr41xx pipeline clock is derived from 18.432MHz multiplied
 * by a value selected by the CLKSEL pins, which is reported in the
 * BCU clock speed register (I hope!).  
 */

long
_sbd_pipefreq (void)
{
    volatile struct vr41xxbcu *bcu = PA_TO_KVA1 (BCU_BASE);
    unsigned int div, revid;

    div = ((bcu->bcu_clkspeed & BCUCLKSPEED_CLKSP_MASK) 
	   >> BCUCLKSPEED_CLKSP_SHIFT);
    if (div == 0)
	div = 1;

    revid = ((bcu->bcu_revid & BCUREVID_RID_MASK)
	     >> BCUREVID_RID_SHIFT);
    switch (revid) {
    case RID_VR4102:
	return (18432000 * 32) / div;
    case RID_VR4111:
    case RID_VR4121:
    case RID_VR4122:		/* guess */
    default:
	return (18432000 * 64) / div;
    }
}

/* 
 * The Vr41xx internal Tclock run at a divisor of the pipeline 
 * clock (Pclock).  Return that divisor.
 */

long
_sbd_tclkdiv (void)
{
    volatile struct vr41xxbcu *bcu = PA_TO_KVA1 (BCU_BASE);
    unsigned int revid = ((bcu->bcu_revid & BCUREVID_RID_MASK)
			  >> BCUREVID_RID_SHIFT);

    switch (revid) {
    case RID_VR4102:
    case RID_VR4111:
	if ((bcu->bcu_clkspeed & BCUCLKSPEED_DIV2B) == 0)
	    return 2;
	if ((bcu->bcu_clkspeed & BCUCLKSPEED_DIV3B) == 0)
	    return 3;
	if ((bcu->bcu_clkspeed & BCUCLKSPEED_DIV4B) == 0)
	    return 4;
	/* ??? what if none are set to zero */
	return 1;
	
    case RID_VR4121:
    case RID_VR4122:
    default:
	return ((bcu->bcu_clkspeed & BCUCLKSPEED_DIVT_MASK) >> 
		BCUCLKSPEED_DIVT_SHIFT);
    }
}


/* 
 * The bus clock runs at TClock / 4.
 */

long
_sbd_cpufreq (void)
{
    return _sbd_pipefreq () / _sbd_tclkdiv () / 4;
}
