|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * clock_speed.c - Determine the best guess for the processor and bus
24: * speed buy using the values returned by run_clock_test.
25: *
26: * (c) Apple Computer, Inc. 1998-9
27: *
28: * Writen by: Josh de Cesare
29: *
30: */
31:
32:
33: #include <ppc/machine_routines.h>
34:
35: #include <pexpert/ppc/powermac.h>
36:
37: // prototypes
38: extern void pe_run_clock_test(void *tmp);
39: void pe_do_clock_test(unsigned int via_addr,
40: int num_speeds, unsigned long *speed_list);
41:
42: // Threshold for bus speed matches.
43: #define kMaxFreqDiff (30000)
44:
45: // This is the structure for the data that get passed to pe_run_clock_test.
46: struct clock_test_data {
47: unsigned int via_addr;
48: unsigned int via_ticks;
49: unsigned int dec_ticks;
50: };
51:
52: // glocal variables to simplify some stuff.
53: static long bus_freq_num, bus_freq_den, cpu_pll;
54:
55: // PE_Determine_Clock_Speeds is called by the via driver in IOKit
56: // It uses the numbers generated by pe_do_clock_test and reports
57: // the cleaned up values to the rest of the OS.
58: void PE_Determine_Clock_Speeds(unsigned int via_addr, int num_speeds,
59: unsigned long *speed_list)
60: {
61: boolean_t oldLevel;
62:
63: oldLevel = ml_set_interrupts_enabled(FALSE);
64: pe_do_clock_test(via_addr, num_speeds, speed_list);
65: ml_set_interrupts_enabled(oldLevel);
66:
67: // Report the bus clock rate as is.
68: powermac_info.bus_clock_rate_num = bus_freq_num;
69: powermac_info.bus_clock_rate_den = bus_freq_den;
70:
71: // pll multipliers are in halfs so set the denominator to 2.
72: powermac_info.bus_to_cpu_rate_num = cpu_pll;
73: powermac_info.bus_to_cpu_rate_den = 2;
74:
75: // The decrementer rate is one fourth the bus rate.
76: powermac_info.bus_to_dec_rate_num = 1;
77: powermac_info.bus_to_dec_rate_den = 4;
78:
79: PE_call_timebase_callback();
80: }
81:
82: // pe_do_clock_test uses the number from pe_run_clock_test to
83: // find a best fit guess for the bus speed.
84: void pe_do_clock_test(unsigned int via_addr,
85: int num_speeds, unsigned long *speed_list)
86: {
87: struct clock_test_data clock_test_data;
88: long cnt, diff, raw_cpu_freq, raw_bus_freq, tmp_bus_freq,
89: last_bus_freq, tries = 10;
90:
91: // Save the via addr so the asm part can use it.
92: clock_test_data.via_addr = via_addr;
93:
94: // Keep looping until it matches the last try.
95: bus_freq_num = 0;
96: do {
97: last_bus_freq = bus_freq_num;
98:
99: // The the asm part to do the real work.
100: pe_run_clock_test((void *)&clock_test_data);
101:
102: // First find the pll mode. Allow any integer times two.
103: cpu_pll = 10000000 / clock_test_data.dec_ticks;
104: cpu_pll = (cpu_pll / 2) + (cpu_pll & 1);
105:
106: // Using 64 bit math figure out the raw bus speed.
107: // 0xBF401675E5DULL is 1 / 1.27655us times 2 ^ 24.
108: raw_bus_freq = ((0xBF401675E5DULL * clock_test_data.dec_ticks) /
109: clock_test_data.via_ticks) >> 22;
110:
111: // use the pll mode and the raw bus speed to find the raw cpu speed.
112: raw_cpu_freq = raw_bus_freq * cpu_pll / 2;
113:
114: // Look to see if the bus speed is close to one of the
115: // speeds in the table.
116: for (cnt = 0; cnt < num_speeds; cnt++) {
117: bus_freq_num = speed_list[cnt * 2];
118: bus_freq_den = speed_list[cnt * 2 + 1];
119: diff = bus_freq_num - raw_bus_freq * bus_freq_den;
120: if (diff < 0) diff = -diff;
121:
122: if (diff < kMaxFreqDiff * bus_freq_den) break;
123: }
124: if (cnt != num_speeds) continue;
125:
126: // Look to see if the bus speed is close to n * 0.5 MHz
127: tmp_bus_freq = ((raw_bus_freq + 250000) / 500000) * 500000;
128:
129: diff = tmp_bus_freq - raw_bus_freq;
130: if (diff < 0) diff = -diff;
131:
132: if (diff < kMaxFreqDiff) {
133: bus_freq_num = tmp_bus_freq;
134: bus_freq_den = 1;
135: continue;
136: }
137:
138: // Look to see if the bus speed is close to n * 50/3 MHz
139: tmp_bus_freq = ((raw_bus_freq * 3 + 25000000) / 50000000) * 50000000;
140:
141: diff = tmp_bus_freq - raw_bus_freq * 3;
142: if (diff < 0) diff = -diff;
143:
144: if (diff < kMaxFreqDiff * 3) {
145: bus_freq_num = tmp_bus_freq;
146: bus_freq_den = 3;
147: continue;
148: }
149:
150: // Since all else failed return the raw bus speed
151: bus_freq_num = raw_bus_freq;
152: bus_freq_den = 1;
153: } while ((bus_freq_num != last_bus_freq) && tries--);
154: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.