2005-04-16 15:20:36 -07:00
/*
* bcu . c , Bus Control Unit routines for the NEC VR4100 series .
*
2013-01-22 12:59:30 +01:00
* Copyright ( C ) 2002 MontaVista Software Inc .
2009-07-03 00:39:38 +09:00
* Author : Yoichi Yuasa < source @ mvista . com >
* Copyright ( C ) 2003 - 2005 Yoichi Yuasa < yuasa @ linux - mips . org >
2005-04-16 15:20:36 -07:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
/*
* Changes :
2009-07-03 00:39:38 +09:00
* MontaVista Software Inc . < source @ mvista . com >
2005-04-16 15:20:36 -07:00
* - New creation , NEC VR4122 and VR4131 are supported .
* - Added support for NEC VR4111 and VR4121 .
*
2009-07-03 00:39:38 +09:00
* Yoichi Yuasa < yuasa @ linux - mips . org >
2005-04-16 15:20:36 -07:00
* - Added support for NEC VR4133 .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/smp.h>
# include <linux/types.h>
# include <asm/cpu.h>
# include <asm/io.h>
# define CLKSPEEDREG_TYPE1 (void __iomem *)KSEG1ADDR(0x0b000014)
# define CLKSPEEDREG_TYPE2 (void __iomem *)KSEG1ADDR(0x0f000014)
# define CLKSP(x) ((x) & 0x001f)
# define CLKSP_VR4133(x) ((x) & 0x0007)
# define DIV2B 0x8000
# define DIV3B 0x4000
# define DIV4B 0x2000
# define DIVT(x) (((x) & 0xf000) >> 12)
# define DIVVT(x) (((x) & 0x0f00) >> 8)
# define TDIVMODE(x) (2 << (((x) & 0x1000) >> 12))
# define VTDIVMODE(x) (((x) & 0x0700) >> 8)
static unsigned long vr41xx_vtclock ;
static unsigned long vr41xx_tclock ;
unsigned long vr41xx_get_vtclock_frequency ( void )
{
return vr41xx_vtclock ;
}
EXPORT_SYMBOL_GPL ( vr41xx_get_vtclock_frequency ) ;
unsigned long vr41xx_get_tclock_frequency ( void )
{
return vr41xx_tclock ;
}
EXPORT_SYMBOL_GPL ( vr41xx_get_tclock_frequency ) ;
static inline uint16_t read_clkspeed ( void )
{
2007-10-11 23:46:15 +01:00
switch ( current_cpu_type ( ) ) {
2005-04-16 15:20:36 -07:00
case CPU_VR4111 :
case CPU_VR4121 : return readw ( CLKSPEEDREG_TYPE1 ) ;
case CPU_VR4122 :
case CPU_VR4131 :
case CPU_VR4133 : return readw ( CLKSPEEDREG_TYPE2 ) ;
default :
printk ( KERN_INFO " Unexpected CPU of NEC VR4100 series \n " ) ;
break ;
}
return 0 ;
}
static inline unsigned long calculate_pclock ( uint16_t clkspeed )
{
unsigned long pclock = 0 ;
2007-10-11 23:46:15 +01:00
switch ( current_cpu_type ( ) ) {
2005-04-16 15:20:36 -07:00
case CPU_VR4111 :
case CPU_VR4121 :
pclock = 18432000 * 64 ;
pclock / = CLKSP ( clkspeed ) ;
break ;
case CPU_VR4122 :
pclock = 18432000 * 98 ;
pclock / = CLKSP ( clkspeed ) ;
break ;
case CPU_VR4131 :
pclock = 18432000 * 108 ;
pclock / = CLKSP ( clkspeed ) ;
break ;
case CPU_VR4133 :
switch ( CLKSP_VR4133 ( clkspeed ) ) {
case 0 :
pclock = 133000000 ;
break ;
case 1 :
pclock = 149000000 ;
break ;
case 2 :
pclock = 165900000 ;
break ;
case 3 :
pclock = 199100000 ;
break ;
case 4 :
pclock = 265900000 ;
break ;
default :
printk ( KERN_INFO " Unknown PClock speed for NEC VR4133 \n " ) ;
break ;
}
break ;
default :
printk ( KERN_INFO " Unexpected CPU of NEC VR4100 series \n " ) ;
break ;
}
printk ( KERN_INFO " PClock: %ldHz \n " , pclock ) ;
return pclock ;
}
static inline unsigned long calculate_vtclock ( uint16_t clkspeed , unsigned long pclock )
{
unsigned long vtclock = 0 ;
2007-10-11 23:46:15 +01:00
switch ( current_cpu_type ( ) ) {
2005-04-16 15:20:36 -07:00
case CPU_VR4111 :
/* The NEC VR4111 doesn't have the VTClock. */
break ;
case CPU_VR4121 :
vtclock = pclock ;
/* DIVVT == 9 Divide by 1.5 . VTClock = (PClock * 6) / 9 */
if ( DIVVT ( clkspeed ) = = 9 )
vtclock = pclock * 6 ;
/* DIVVT == 10 Divide by 2.5 . VTClock = (PClock * 4) / 10 */
else if ( DIVVT ( clkspeed ) = = 10 )
vtclock = pclock * 4 ;
vtclock / = DIVVT ( clkspeed ) ;
printk ( KERN_INFO " VTClock: %ldHz \n " , vtclock ) ;
break ;
case CPU_VR4122 :
if ( VTDIVMODE ( clkspeed ) = = 7 )
vtclock = pclock / 1 ;
else if ( VTDIVMODE ( clkspeed ) = = 1 )
vtclock = pclock / 2 ;
else
vtclock = pclock / VTDIVMODE ( clkspeed ) ;
printk ( KERN_INFO " VTClock: %ldHz \n " , vtclock ) ;
break ;
case CPU_VR4131 :
case CPU_VR4133 :
vtclock = pclock / VTDIVMODE ( clkspeed ) ;
printk ( KERN_INFO " VTClock: %ldHz \n " , vtclock ) ;
break ;
default :
printk ( KERN_INFO " Unexpected CPU of NEC VR4100 series \n " ) ;
break ;
}
return vtclock ;
}
static inline unsigned long calculate_tclock ( uint16_t clkspeed , unsigned long pclock ,
2013-01-22 12:59:30 +01:00
unsigned long vtclock )
2005-04-16 15:20:36 -07:00
{
unsigned long tclock = 0 ;
2007-10-11 23:46:15 +01:00
switch ( current_cpu_type ( ) ) {
2005-04-16 15:20:36 -07:00
case CPU_VR4111 :
if ( ! ( clkspeed & DIV2B ) )
2006-03-11 08:18:41 +00:00
tclock = pclock / 2 ;
2005-04-16 15:20:36 -07:00
else if ( ! ( clkspeed & DIV3B ) )
2006-03-11 08:18:41 +00:00
tclock = pclock / 3 ;
2005-04-16 15:20:36 -07:00
else if ( ! ( clkspeed & DIV4B ) )
2006-03-11 08:18:41 +00:00
tclock = pclock / 4 ;
2005-04-16 15:20:36 -07:00
break ;
case CPU_VR4121 :
tclock = pclock / DIVT ( clkspeed ) ;
break ;
case CPU_VR4122 :
case CPU_VR4131 :
case CPU_VR4133 :
tclock = vtclock / TDIVMODE ( clkspeed ) ;
break ;
default :
printk ( KERN_INFO " Unexpected CPU of NEC VR4100 series \n " ) ;
break ;
}
printk ( KERN_INFO " TClock: %ldHz \n " , tclock ) ;
return tclock ;
}
void vr41xx_calculate_clock_frequency ( void )
{
unsigned long pclock ;
uint16_t clkspeed ;
clkspeed = read_clkspeed ( ) ;
pclock = calculate_pclock ( clkspeed ) ;
vr41xx_vtclock = calculate_vtclock ( clkspeed , pclock ) ;
vr41xx_tclock = calculate_tclock ( clkspeed , pclock , vr41xx_vtclock ) ;
}
EXPORT_SYMBOL_GPL ( vr41xx_calculate_clock_frequency ) ;