Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* us2e_cpufreq.c: UltraSPARC-IIe cpu frequency support
0003  *
0004  * Copyright (C) 2003 David S. Miller (davem@redhat.com)
0005  *
0006  * Many thanks to Dominik Brodowski for fixing up the cpufreq
0007  * infrastructure in order to make this driver easier to implement.
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/sched.h>
0013 #include <linux/smp.h>
0014 #include <linux/cpufreq.h>
0015 #include <linux/threads.h>
0016 #include <linux/slab.h>
0017 #include <linux/delay.h>
0018 #include <linux/init.h>
0019 
0020 #include <asm/asi.h>
0021 #include <asm/timer.h>
0022 
0023 static struct cpufreq_driver *cpufreq_us2e_driver;
0024 
0025 struct us2e_freq_percpu_info {
0026     struct cpufreq_frequency_table table[6];
0027 };
0028 
0029 /* Indexed by cpu number. */
0030 static struct us2e_freq_percpu_info *us2e_freq_table;
0031 
0032 #define HBIRD_MEM_CNTL0_ADDR    0x1fe0000f010UL
0033 #define HBIRD_ESTAR_MODE_ADDR   0x1fe0000f080UL
0034 
0035 /* UltraSPARC-IIe has five dividers: 1, 2, 4, 6, and 8.  These are controlled
0036  * in the ESTAR mode control register.
0037  */
0038 #define ESTAR_MODE_DIV_1    0x0000000000000000UL
0039 #define ESTAR_MODE_DIV_2    0x0000000000000001UL
0040 #define ESTAR_MODE_DIV_4    0x0000000000000003UL
0041 #define ESTAR_MODE_DIV_6    0x0000000000000002UL
0042 #define ESTAR_MODE_DIV_8    0x0000000000000004UL
0043 #define ESTAR_MODE_DIV_MASK 0x0000000000000007UL
0044 
0045 #define MCTRL0_SREFRESH_ENAB    0x0000000000010000UL
0046 #define MCTRL0_REFR_COUNT_MASK  0x0000000000007f00UL
0047 #define MCTRL0_REFR_COUNT_SHIFT 8
0048 #define MCTRL0_REFR_INTERVAL    7800
0049 #define MCTRL0_REFR_CLKS_P_CNT  64
0050 
0051 static unsigned long read_hbreg(unsigned long addr)
0052 {
0053     unsigned long ret;
0054 
0055     __asm__ __volatile__("ldxa  [%1] %2, %0"
0056                  : "=&r" (ret)
0057                  : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
0058     return ret;
0059 }
0060 
0061 static void write_hbreg(unsigned long addr, unsigned long val)
0062 {
0063     __asm__ __volatile__("stxa  %0, [%1] %2\n\t"
0064                  "membar    #Sync"
0065                  : /* no outputs */
0066                  : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E)
0067                  : "memory");
0068     if (addr == HBIRD_ESTAR_MODE_ADDR) {
0069         /* Need to wait 16 clock cycles for the PLL to lock.  */
0070         udelay(1);
0071     }
0072 }
0073 
0074 static void self_refresh_ctl(int enable)
0075 {
0076     unsigned long mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
0077 
0078     if (enable)
0079         mctrl |= MCTRL0_SREFRESH_ENAB;
0080     else
0081         mctrl &= ~MCTRL0_SREFRESH_ENAB;
0082     write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl);
0083     (void) read_hbreg(HBIRD_MEM_CNTL0_ADDR);
0084 }
0085 
0086 static void frob_mem_refresh(int cpu_slowing_down,
0087                  unsigned long clock_tick,
0088                  unsigned long old_divisor, unsigned long divisor)
0089 {
0090     unsigned long old_refr_count, refr_count, mctrl;
0091 
0092     refr_count  = (clock_tick * MCTRL0_REFR_INTERVAL);
0093     refr_count /= (MCTRL0_REFR_CLKS_P_CNT * divisor * 1000000000UL);
0094 
0095     mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
0096     old_refr_count = (mctrl & MCTRL0_REFR_COUNT_MASK)
0097         >> MCTRL0_REFR_COUNT_SHIFT;
0098 
0099     mctrl &= ~MCTRL0_REFR_COUNT_MASK;
0100     mctrl |= refr_count << MCTRL0_REFR_COUNT_SHIFT;
0101     write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl);
0102     mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
0103 
0104     if (cpu_slowing_down && !(mctrl & MCTRL0_SREFRESH_ENAB)) {
0105         unsigned long usecs;
0106 
0107         /* We have to wait for both refresh counts (old
0108          * and new) to go to zero.
0109          */
0110         usecs = (MCTRL0_REFR_CLKS_P_CNT *
0111              (refr_count + old_refr_count) *
0112              1000000UL *
0113              old_divisor) / clock_tick;
0114         udelay(usecs + 1UL);
0115     }
0116 }
0117 
0118 static void us2e_transition(unsigned long estar, unsigned long new_bits,
0119                 unsigned long clock_tick,
0120                 unsigned long old_divisor, unsigned long divisor)
0121 {
0122     estar &= ~ESTAR_MODE_DIV_MASK;
0123 
0124     /* This is based upon the state transition diagram in the IIe manual.  */
0125     if (old_divisor == 2 && divisor == 1) {
0126         self_refresh_ctl(0);
0127         write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
0128         frob_mem_refresh(0, clock_tick, old_divisor, divisor);
0129     } else if (old_divisor == 1 && divisor == 2) {
0130         frob_mem_refresh(1, clock_tick, old_divisor, divisor);
0131         write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
0132         self_refresh_ctl(1);
0133     } else if (old_divisor == 1 && divisor > 2) {
0134         us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick,
0135                 1, 2);
0136         us2e_transition(estar, new_bits, clock_tick,
0137                 2, divisor);
0138     } else if (old_divisor > 2 && divisor == 1) {
0139         us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick,
0140                 old_divisor, 2);
0141         us2e_transition(estar, new_bits, clock_tick,
0142                 2, divisor);
0143     } else if (old_divisor < divisor) {
0144         frob_mem_refresh(0, clock_tick, old_divisor, divisor);
0145         write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
0146     } else if (old_divisor > divisor) {
0147         write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
0148         frob_mem_refresh(1, clock_tick, old_divisor, divisor);
0149     } else {
0150         BUG();
0151     }
0152 }
0153 
0154 static unsigned long index_to_estar_mode(unsigned int index)
0155 {
0156     switch (index) {
0157     case 0:
0158         return ESTAR_MODE_DIV_1;
0159 
0160     case 1:
0161         return ESTAR_MODE_DIV_2;
0162 
0163     case 2:
0164         return ESTAR_MODE_DIV_4;
0165 
0166     case 3:
0167         return ESTAR_MODE_DIV_6;
0168 
0169     case 4:
0170         return ESTAR_MODE_DIV_8;
0171 
0172     default:
0173         BUG();
0174     }
0175 }
0176 
0177 static unsigned long index_to_divisor(unsigned int index)
0178 {
0179     switch (index) {
0180     case 0:
0181         return 1;
0182 
0183     case 1:
0184         return 2;
0185 
0186     case 2:
0187         return 4;
0188 
0189     case 3:
0190         return 6;
0191 
0192     case 4:
0193         return 8;
0194 
0195     default:
0196         BUG();
0197     }
0198 }
0199 
0200 static unsigned long estar_to_divisor(unsigned long estar)
0201 {
0202     unsigned long ret;
0203 
0204     switch (estar & ESTAR_MODE_DIV_MASK) {
0205     case ESTAR_MODE_DIV_1:
0206         ret = 1;
0207         break;
0208     case ESTAR_MODE_DIV_2:
0209         ret = 2;
0210         break;
0211     case ESTAR_MODE_DIV_4:
0212         ret = 4;
0213         break;
0214     case ESTAR_MODE_DIV_6:
0215         ret = 6;
0216         break;
0217     case ESTAR_MODE_DIV_8:
0218         ret = 8;
0219         break;
0220     default:
0221         BUG();
0222     }
0223 
0224     return ret;
0225 }
0226 
0227 static void __us2e_freq_get(void *arg)
0228 {
0229     unsigned long *estar = arg;
0230 
0231     *estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR);
0232 }
0233 
0234 static unsigned int us2e_freq_get(unsigned int cpu)
0235 {
0236     unsigned long clock_tick, estar;
0237 
0238     clock_tick = sparc64_get_clock_tick(cpu) / 1000;
0239     if (smp_call_function_single(cpu, __us2e_freq_get, &estar, 1))
0240         return 0;
0241 
0242     return clock_tick / estar_to_divisor(estar);
0243 }
0244 
0245 static void __us2e_freq_target(void *arg)
0246 {
0247     unsigned int cpu = smp_processor_id();
0248     unsigned int *index = arg;
0249     unsigned long new_bits, new_freq;
0250     unsigned long clock_tick, divisor, old_divisor, estar;
0251 
0252     new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000;
0253     new_bits = index_to_estar_mode(*index);
0254     divisor = index_to_divisor(*index);
0255     new_freq /= divisor;
0256 
0257     estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR);
0258 
0259     old_divisor = estar_to_divisor(estar);
0260 
0261     if (old_divisor != divisor) {
0262         us2e_transition(estar, new_bits, clock_tick * 1000,
0263                 old_divisor, divisor);
0264     }
0265 }
0266 
0267 static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
0268 {
0269     unsigned int cpu = policy->cpu;
0270 
0271     return smp_call_function_single(cpu, __us2e_freq_target, &index, 1);
0272 }
0273 
0274 static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
0275 {
0276     unsigned int cpu = policy->cpu;
0277     unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000;
0278     struct cpufreq_frequency_table *table =
0279         &us2e_freq_table[cpu].table[0];
0280 
0281     table[0].driver_data = 0;
0282     table[0].frequency = clock_tick / 1;
0283     table[1].driver_data = 1;
0284     table[1].frequency = clock_tick / 2;
0285     table[2].driver_data = 2;
0286     table[2].frequency = clock_tick / 4;
0287     table[2].driver_data = 3;
0288     table[2].frequency = clock_tick / 6;
0289     table[2].driver_data = 4;
0290     table[2].frequency = clock_tick / 8;
0291     table[2].driver_data = 5;
0292     table[3].frequency = CPUFREQ_TABLE_END;
0293 
0294     policy->cpuinfo.transition_latency = 0;
0295     policy->cur = clock_tick;
0296     policy->freq_table = table;
0297 
0298     return 0;
0299 }
0300 
0301 static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
0302 {
0303     if (cpufreq_us2e_driver)
0304         us2e_freq_target(policy, 0);
0305 
0306     return 0;
0307 }
0308 
0309 static int __init us2e_freq_init(void)
0310 {
0311     unsigned long manuf, impl, ver;
0312     int ret;
0313 
0314     if (tlb_type != spitfire)
0315         return -ENODEV;
0316 
0317     __asm__("rdpr %%ver, %0" : "=r" (ver));
0318     manuf = ((ver >> 48) & 0xffff);
0319     impl  = ((ver >> 32) & 0xffff);
0320 
0321     if (manuf == 0x17 && impl == 0x13) {
0322         struct cpufreq_driver *driver;
0323 
0324         ret = -ENOMEM;
0325         driver = kzalloc(sizeof(*driver), GFP_KERNEL);
0326         if (!driver)
0327             goto err_out;
0328 
0329         us2e_freq_table = kzalloc((NR_CPUS * sizeof(*us2e_freq_table)),
0330             GFP_KERNEL);
0331         if (!us2e_freq_table)
0332             goto err_out;
0333 
0334         driver->init = us2e_freq_cpu_init;
0335         driver->verify = cpufreq_generic_frequency_table_verify;
0336         driver->target_index = us2e_freq_target;
0337         driver->get = us2e_freq_get;
0338         driver->exit = us2e_freq_cpu_exit;
0339         strcpy(driver->name, "UltraSPARC-IIe");
0340 
0341         cpufreq_us2e_driver = driver;
0342         ret = cpufreq_register_driver(driver);
0343         if (ret)
0344             goto err_out;
0345 
0346         return 0;
0347 
0348 err_out:
0349         if (driver) {
0350             kfree(driver);
0351             cpufreq_us2e_driver = NULL;
0352         }
0353         kfree(us2e_freq_table);
0354         us2e_freq_table = NULL;
0355         return ret;
0356     }
0357 
0358     return -ENODEV;
0359 }
0360 
0361 static void __exit us2e_freq_exit(void)
0362 {
0363     if (cpufreq_us2e_driver) {
0364         cpufreq_unregister_driver(cpufreq_us2e_driver);
0365         kfree(cpufreq_us2e_driver);
0366         cpufreq_us2e_driver = NULL;
0367         kfree(us2e_freq_table);
0368         us2e_freq_table = NULL;
0369     }
0370 }
0371 
0372 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
0373 MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-IIe");
0374 MODULE_LICENSE("GPL");
0375 
0376 module_init(us2e_freq_init);
0377 module_exit(us2e_freq_exit);