linux/arch/mips/vr41xx/common/bcu.c
<<
>>
Prefs
   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);
 211