116 lines
3.4 KiB
Python
116 lines
3.4 KiB
Python
|
"""
|
||
|
This is an auxiliary script that is used to compute valid PLL values to set
|
||
|
the CPU frequency to a given value. The algorithm here appears as C code
|
||
|
for the machine.freq() function.
|
||
|
"""
|
||
|
|
||
|
def close_int(x):
|
||
|
return abs(x - round(x)) < 0.01
|
||
|
|
||
|
# original version that requires N/M to be an integer (for simplicity)
|
||
|
def compute_pll(hse, sys):
|
||
|
for P in (2, 4, 6, 8): # allowed values of P
|
||
|
Q = sys * P / 48
|
||
|
NbyM = sys * P / hse
|
||
|
# N/M and Q must be integers
|
||
|
if not (close_int(NbyM) and close_int(Q)):
|
||
|
continue
|
||
|
# VCO_OUT must be between 192MHz and 432MHz
|
||
|
if not (192 <= hse * NbyM <= 432):
|
||
|
continue
|
||
|
# compute M
|
||
|
M = int(192 // NbyM)
|
||
|
while hse > 2 * M or NbyM * M < 192:
|
||
|
M += 1
|
||
|
# VCO_IN must be between 1MHz and 2MHz (2MHz recommended)
|
||
|
if not (M <= hse):
|
||
|
continue
|
||
|
# compute N
|
||
|
N = NbyM * M
|
||
|
# N and Q are restricted
|
||
|
if not (192 <= N <= 432 and 2 <= Q <= 15):
|
||
|
continue
|
||
|
# found valid values
|
||
|
assert NbyM == N // M
|
||
|
return (M, N, P, Q)
|
||
|
# no valid values found
|
||
|
return None
|
||
|
|
||
|
# improved version that doesn't require N/M to be an integer
|
||
|
def compute_pll2(hse, sys):
|
||
|
for P in (2, 4, 6, 8): # allowed values of P
|
||
|
Q = sys * P / 48
|
||
|
# Q must be an integer in a set range
|
||
|
if not (close_int(Q) and 2 <= Q <= 15):
|
||
|
continue
|
||
|
NbyM = sys * P / hse
|
||
|
# VCO_OUT must be between 192MHz and 432MHz
|
||
|
if not (192 <= hse * NbyM <= 432):
|
||
|
continue
|
||
|
# compute M
|
||
|
M = 192 // NbyM # starting value
|
||
|
while hse > 2 * M or NbyM * M < 192 or not close_int(NbyM * M):
|
||
|
M += 1
|
||
|
# VCO_IN must be between 1MHz and 2MHz (2MHz recommended)
|
||
|
if not (M <= hse):
|
||
|
continue
|
||
|
# compute N
|
||
|
N = NbyM * M
|
||
|
# N must be an integer
|
||
|
if not close_int(N):
|
||
|
continue
|
||
|
# N is restricted
|
||
|
if not (192 <= N <= 432):
|
||
|
continue
|
||
|
# found valid values
|
||
|
return (M, N, P, Q)
|
||
|
# no valid values found
|
||
|
return None
|
||
|
|
||
|
def verify_and_print_pll(hse, sys, pll):
|
||
|
M, N, P, Q = pll
|
||
|
|
||
|
# compute derived quantities
|
||
|
vco_in = hse / M
|
||
|
vco_out = hse * N / M
|
||
|
pllck = hse / M * N / P
|
||
|
pll48ck = hse / M * N / Q
|
||
|
|
||
|
# verify ints
|
||
|
assert close_int(M)
|
||
|
assert close_int(N)
|
||
|
assert close_int(P)
|
||
|
assert close_int(Q)
|
||
|
|
||
|
# verify range
|
||
|
assert 2 <= M <= 63
|
||
|
assert 192 <= N <= 432
|
||
|
assert P in (2, 4, 6, 8)
|
||
|
assert 2 <= Q <= 15
|
||
|
assert 1 <= vco_in <= 2
|
||
|
assert 192 <= vco_out <= 432
|
||
|
|
||
|
# print out values
|
||
|
print(out_format % (sys, M, N, P, Q, vco_in, vco_out, pllck, pll48ck))
|
||
|
|
||
|
def main():
|
||
|
global out_format
|
||
|
import sys
|
||
|
if len(sys.argv) != 2:
|
||
|
print("usage: pllvalues.py <hse in MHz>")
|
||
|
sys.exit(1)
|
||
|
hse_value = int(sys.argv[1])
|
||
|
print("HSE =", hse_value, "MHz")
|
||
|
print("sys : M N P Q : VCO_IN VCO_OUT PLLCK PLL48CK")
|
||
|
out_format = "%3u : %2u %.1f %.2f %.2f : %5.2f %6.2f %6.2f %6.2f"
|
||
|
n_valid = 0
|
||
|
for sysclk in range(1, 217):
|
||
|
pll = compute_pll2(hse_value, sysclk)
|
||
|
if pll is not None:
|
||
|
n_valid += 1
|
||
|
verify_and_print_pll(hse_value, sysclk, pll)
|
||
|
print("found %u valid configurations" % n_valid)
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|