18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * bcu.c, Bus Control Unit routines for the NEC VR4100 series. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2002 MontaVista Software Inc. 68c2ecf20Sopenharmony_ci * Author: Yoichi Yuasa <source@mvista.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@linux-mips.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * Changes: 118c2ecf20Sopenharmony_ci * MontaVista Software Inc. <source@mvista.com> 128c2ecf20Sopenharmony_ci * - New creation, NEC VR4122 and VR4131 are supported. 138c2ecf20Sopenharmony_ci * - Added support for NEC VR4111 and VR4121. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Yoichi Yuasa <yuasa@linux-mips.org> 168c2ecf20Sopenharmony_ci * - Added support for NEC VR4133. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci#include <linux/export.h> 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/smp.h> 218c2ecf20Sopenharmony_ci#include <linux/types.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <asm/cpu-type.h> 248c2ecf20Sopenharmony_ci#include <asm/cpu.h> 258c2ecf20Sopenharmony_ci#include <asm/io.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define CLKSPEEDREG_TYPE1 (void __iomem *)KSEG1ADDR(0x0b000014) 288c2ecf20Sopenharmony_ci#define CLKSPEEDREG_TYPE2 (void __iomem *)KSEG1ADDR(0x0f000014) 298c2ecf20Sopenharmony_ci #define CLKSP(x) ((x) & 0x001f) 308c2ecf20Sopenharmony_ci #define CLKSP_VR4133(x) ((x) & 0x0007) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci #define DIV2B 0x8000 338c2ecf20Sopenharmony_ci #define DIV3B 0x4000 348c2ecf20Sopenharmony_ci #define DIV4B 0x2000 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci #define DIVT(x) (((x) & 0xf000) >> 12) 378c2ecf20Sopenharmony_ci #define DIVVT(x) (((x) & 0x0f00) >> 8) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci #define TDIVMODE(x) (2 << (((x) & 0x1000) >> 12)) 408c2ecf20Sopenharmony_ci #define VTDIVMODE(x) (((x) & 0x0700) >> 8) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic unsigned long vr41xx_vtclock; 438c2ecf20Sopenharmony_cistatic unsigned long vr41xx_tclock; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciunsigned long vr41xx_get_vtclock_frequency(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return vr41xx_vtclock; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vr41xx_get_vtclock_frequency); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciunsigned long vr41xx_get_tclock_frequency(void) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci return vr41xx_tclock; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vr41xx_get_tclock_frequency); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic inline uint16_t read_clkspeed(void) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci switch (current_cpu_type()) { 628c2ecf20Sopenharmony_ci case CPU_VR4111: 638c2ecf20Sopenharmony_ci case CPU_VR4121: return readw(CLKSPEEDREG_TYPE1); 648c2ecf20Sopenharmony_ci case CPU_VR4122: 658c2ecf20Sopenharmony_ci case CPU_VR4131: 668c2ecf20Sopenharmony_ci case CPU_VR4133: return readw(CLKSPEEDREG_TYPE2); 678c2ecf20Sopenharmony_ci default: 688c2ecf20Sopenharmony_ci printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return 0; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic inline unsigned long calculate_pclock(uint16_t clkspeed) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci unsigned long pclock = 0; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci switch (current_cpu_type()) { 808c2ecf20Sopenharmony_ci case CPU_VR4111: 818c2ecf20Sopenharmony_ci case CPU_VR4121: 828c2ecf20Sopenharmony_ci pclock = 18432000 * 64; 838c2ecf20Sopenharmony_ci pclock /= CLKSP(clkspeed); 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci case CPU_VR4122: 868c2ecf20Sopenharmony_ci pclock = 18432000 * 98; 878c2ecf20Sopenharmony_ci pclock /= CLKSP(clkspeed); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci case CPU_VR4131: 908c2ecf20Sopenharmony_ci pclock = 18432000 * 108; 918c2ecf20Sopenharmony_ci pclock /= CLKSP(clkspeed); 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci case CPU_VR4133: 948c2ecf20Sopenharmony_ci switch (CLKSP_VR4133(clkspeed)) { 958c2ecf20Sopenharmony_ci case 0: 968c2ecf20Sopenharmony_ci pclock = 133000000; 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci case 1: 998c2ecf20Sopenharmony_ci pclock = 149000000; 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci case 2: 1028c2ecf20Sopenharmony_ci pclock = 165900000; 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci case 3: 1058c2ecf20Sopenharmony_ci pclock = 199100000; 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci case 4: 1088c2ecf20Sopenharmony_ci pclock = 265900000; 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci default: 1118c2ecf20Sopenharmony_ci printk(KERN_INFO "Unknown PClock speed for NEC VR4133\n"); 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci default: 1168c2ecf20Sopenharmony_ci printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci printk(KERN_INFO "PClock: %ldHz\n", pclock); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return pclock; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic inline unsigned long calculate_vtclock(uint16_t clkspeed, unsigned long pclock) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci unsigned long vtclock = 0; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci switch (current_cpu_type()) { 1308c2ecf20Sopenharmony_ci case CPU_VR4111: 1318c2ecf20Sopenharmony_ci /* The NEC VR4111 doesn't have the VTClock. */ 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case CPU_VR4121: 1348c2ecf20Sopenharmony_ci vtclock = pclock; 1358c2ecf20Sopenharmony_ci /* DIVVT == 9 Divide by 1.5 . VTClock = (PClock * 6) / 9 */ 1368c2ecf20Sopenharmony_ci if (DIVVT(clkspeed) == 9) 1378c2ecf20Sopenharmony_ci vtclock = pclock * 6; 1388c2ecf20Sopenharmony_ci /* DIVVT == 10 Divide by 2.5 . VTClock = (PClock * 4) / 10 */ 1398c2ecf20Sopenharmony_ci else if (DIVVT(clkspeed) == 10) 1408c2ecf20Sopenharmony_ci vtclock = pclock * 4; 1418c2ecf20Sopenharmony_ci vtclock /= DIVVT(clkspeed); 1428c2ecf20Sopenharmony_ci printk(KERN_INFO "VTClock: %ldHz\n", vtclock); 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci case CPU_VR4122: 1458c2ecf20Sopenharmony_ci if(VTDIVMODE(clkspeed) == 7) 1468c2ecf20Sopenharmony_ci vtclock = pclock / 1; 1478c2ecf20Sopenharmony_ci else if(VTDIVMODE(clkspeed) == 1) 1488c2ecf20Sopenharmony_ci vtclock = pclock / 2; 1498c2ecf20Sopenharmony_ci else 1508c2ecf20Sopenharmony_ci vtclock = pclock / VTDIVMODE(clkspeed); 1518c2ecf20Sopenharmony_ci printk(KERN_INFO "VTClock: %ldHz\n", vtclock); 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case CPU_VR4131: 1548c2ecf20Sopenharmony_ci case CPU_VR4133: 1558c2ecf20Sopenharmony_ci vtclock = pclock / VTDIVMODE(clkspeed); 1568c2ecf20Sopenharmony_ci printk(KERN_INFO "VTClock: %ldHz\n", vtclock); 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci default: 1598c2ecf20Sopenharmony_ci printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return vtclock; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic inline unsigned long calculate_tclock(uint16_t clkspeed, unsigned long pclock, 1678c2ecf20Sopenharmony_ci unsigned long vtclock) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci unsigned long tclock = 0; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci switch (current_cpu_type()) { 1728c2ecf20Sopenharmony_ci case CPU_VR4111: 1738c2ecf20Sopenharmony_ci if (!(clkspeed & DIV2B)) 1748c2ecf20Sopenharmony_ci tclock = pclock / 2; 1758c2ecf20Sopenharmony_ci else if (!(clkspeed & DIV3B)) 1768c2ecf20Sopenharmony_ci tclock = pclock / 3; 1778c2ecf20Sopenharmony_ci else if (!(clkspeed & DIV4B)) 1788c2ecf20Sopenharmony_ci tclock = pclock / 4; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci case CPU_VR4121: 1818c2ecf20Sopenharmony_ci tclock = pclock / DIVT(clkspeed); 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case CPU_VR4122: 1848c2ecf20Sopenharmony_ci case CPU_VR4131: 1858c2ecf20Sopenharmony_ci case CPU_VR4133: 1868c2ecf20Sopenharmony_ci tclock = vtclock / TDIVMODE(clkspeed); 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci default: 1898c2ecf20Sopenharmony_ci printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci printk(KERN_INFO "TClock: %ldHz\n", tclock); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return tclock; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_civoid vr41xx_calculate_clock_frequency(void) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci unsigned long pclock; 2018c2ecf20Sopenharmony_ci uint16_t clkspeed; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci clkspeed = read_clkspeed(); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci pclock = calculate_pclock(clkspeed); 2068c2ecf20Sopenharmony_ci vr41xx_vtclock = calculate_vtclock(clkspeed, pclock); 2078c2ecf20Sopenharmony_ci vr41xx_tclock = calculate_tclock(clkspeed, pclock, vr41xx_vtclock); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vr41xx_calculate_clock_frequency); 211