bcu.c (4815B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * bcu.c, Bus Control Unit routines for the NEC VR4100 series. 4 * 5 * Copyright (C) 2002 MontaVista Software Inc. 6 * Author: Yoichi Yuasa <source@mvista.com> 7 * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@linux-mips.org> 8 */ 9/* 10 * Changes: 11 * MontaVista Software Inc. <source@mvista.com> 12 * - New creation, NEC VR4122 and VR4131 are supported. 13 * - Added support for NEC VR4111 and VR4121. 14 * 15 * Yoichi Yuasa <yuasa@linux-mips.org> 16 * - Added support for NEC VR4133. 17 */ 18#include <linux/export.h> 19#include <linux/kernel.h> 20#include <linux/smp.h> 21#include <linux/types.h> 22 23#include <asm/cpu-type.h> 24#include <asm/cpu.h> 25#include <asm/io.h> 26 27#define CLKSPEEDREG_TYPE1 (void __iomem *)KSEG1ADDR(0x0b000014) 28#define CLKSPEEDREG_TYPE2 (void __iomem *)KSEG1ADDR(0x0f000014) 29 #define CLKSP(x) ((x) & 0x001f) 30 #define CLKSP_VR4133(x) ((x) & 0x0007) 31 32 #define DIV2B 0x8000 33 #define DIV3B 0x4000 34 #define DIV4B 0x2000 35 36 #define DIVT(x) (((x) & 0xf000) >> 12) 37 #define DIVVT(x) (((x) & 0x0f00) >> 8) 38 39 #define TDIVMODE(x) (2 << (((x) & 0x1000) >> 12)) 40 #define VTDIVMODE(x) (((x) & 0x0700) >> 8) 41 42static unsigned long vr41xx_vtclock; 43static unsigned long vr41xx_tclock; 44 45unsigned long vr41xx_get_vtclock_frequency(void) 46{ 47 return vr41xx_vtclock; 48} 49 50EXPORT_SYMBOL_GPL(vr41xx_get_vtclock_frequency); 51 52unsigned long vr41xx_get_tclock_frequency(void) 53{ 54 return vr41xx_tclock; 55} 56 57EXPORT_SYMBOL_GPL(vr41xx_get_tclock_frequency); 58 59static inline uint16_t read_clkspeed(void) 60{ 61 switch (current_cpu_type()) { 62 case CPU_VR4111: 63 case CPU_VR4121: return readw(CLKSPEEDREG_TYPE1); 64 case CPU_VR4122: 65 case CPU_VR4131: 66 case CPU_VR4133: return readw(CLKSPEEDREG_TYPE2); 67 default: 68 printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); 69 break; 70 } 71 72 return 0; 73} 74 75static inline unsigned long calculate_pclock(uint16_t clkspeed) 76{ 77 unsigned long pclock = 0; 78 79 switch (current_cpu_type()) { 80 case CPU_VR4111: 81 case CPU_VR4121: 82 pclock = 18432000 * 64; 83 pclock /= CLKSP(clkspeed); 84 break; 85 case CPU_VR4122: 86 pclock = 18432000 * 98; 87 pclock /= CLKSP(clkspeed); 88 break; 89 case CPU_VR4131: 90 pclock = 18432000 * 108; 91 pclock /= CLKSP(clkspeed); 92 break; 93 case CPU_VR4133: 94 switch (CLKSP_VR4133(clkspeed)) { 95 case 0: 96 pclock = 133000000; 97 break; 98 case 1: 99 pclock = 149000000; 100 break; 101 case 2: 102 pclock = 165900000; 103 break; 104 case 3: 105 pclock = 199100000; 106 break; 107 case 4: 108 pclock = 265900000; 109 break; 110 default: 111 printk(KERN_INFO "Unknown PClock speed for NEC VR4133\n"); 112 break; 113 } 114 break; 115 default: 116 printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); 117 break; 118 } 119 120 printk(KERN_INFO "PClock: %ldHz\n", pclock); 121 122 return pclock; 123} 124 125static inline unsigned long calculate_vtclock(uint16_t clkspeed, unsigned long pclock) 126{ 127 unsigned long vtclock = 0; 128 129 switch (current_cpu_type()) { 130 case CPU_VR4111: 131 /* The NEC VR4111 doesn't have the VTClock. */ 132 break; 133 case CPU_VR4121: 134 vtclock = pclock; 135 /* DIVVT == 9 Divide by 1.5 . VTClock = (PClock * 6) / 9 */ 136 if (DIVVT(clkspeed) == 9) 137 vtclock = pclock * 6; 138 /* DIVVT == 10 Divide by 2.5 . VTClock = (PClock * 4) / 10 */ 139 else if (DIVVT(clkspeed) == 10) 140 vtclock = pclock * 4; 141 vtclock /= DIVVT(clkspeed); 142 printk(KERN_INFO "VTClock: %ldHz\n", vtclock); 143 break; 144 case CPU_VR4122: 145 if(VTDIVMODE(clkspeed) == 7) 146 vtclock = pclock / 1; 147 else if(VTDIVMODE(clkspeed) == 1) 148 vtclock = pclock / 2; 149 else 150 vtclock = pclock / VTDIVMODE(clkspeed); 151 printk(KERN_INFO "VTClock: %ldHz\n", vtclock); 152 break; 153 case CPU_VR4131: 154 case CPU_VR4133: 155 vtclock = pclock / VTDIVMODE(clkspeed); 156 printk(KERN_INFO "VTClock: %ldHz\n", vtclock); 157 break; 158 default: 159 printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); 160 break; 161 } 162 163 return vtclock; 164} 165 166static inline unsigned long calculate_tclock(uint16_t clkspeed, unsigned long pclock, 167 unsigned long vtclock) 168{ 169 unsigned long tclock = 0; 170 171 switch (current_cpu_type()) { 172 case CPU_VR4111: 173 if (!(clkspeed & DIV2B)) 174 tclock = pclock / 2; 175 else if (!(clkspeed & DIV3B)) 176 tclock = pclock / 3; 177 else if (!(clkspeed & DIV4B)) 178 tclock = pclock / 4; 179 break; 180 case CPU_VR4121: 181 tclock = pclock / DIVT(clkspeed); 182 break; 183 case CPU_VR4122: 184 case CPU_VR4131: 185 case CPU_VR4133: 186 tclock = vtclock / TDIVMODE(clkspeed); 187 break; 188 default: 189 printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); 190 break; 191 } 192 193 printk(KERN_INFO "TClock: %ldHz\n", tclock); 194 195 return tclock; 196} 197 198void vr41xx_calculate_clock_frequency(void) 199{ 200 unsigned long pclock; 201 uint16_t clkspeed; 202 203 clkspeed = read_clkspeed(); 204 205 pclock = calculate_pclock(clkspeed); 206 vr41xx_vtclock = calculate_vtclock(clkspeed, pclock); 207 vr41xx_tclock = calculate_tclock(clkspeed, pclock, vr41xx_vtclock); 208} 209 210EXPORT_SYMBOL_GPL(vr41xx_calculate_clock_frequency);