soc/cores/clock: add divclk_divide/vco_margin support on S7/Ultrascale

This commit is contained in:
Florent Kermarrec 2019-04-15 11:36:42 +02:00
parent f986974d60
commit c252972bef

View file

@ -16,7 +16,8 @@ class S7Clocking(Module, AutoCSR):
clkfbout_mult_frange = (2, 64+1) clkfbout_mult_frange = (2, 64+1)
clkout_divide_range = (1, 128+1) clkout_divide_range = (1, 128+1)
def __init__(self): def __init__(self, vco_margin=0):
self.vco_margin = vco_margin
self.reset = Signal() self.reset = Signal()
self.locked = Signal() self.locked = Signal()
self.clkin_freq = None self.clkin_freq = None
@ -57,30 +58,32 @@ class S7Clocking(Module, AutoCSR):
def compute_config(self): def compute_config(self):
config = {} config = {}
config["divclk_divide"] = 1 for divclk_divide in range(*self.divclk_divide_range):
for clkfbout_mult in range(*self.clkfbout_mult_frange): config["divclk_divide"] = divclk_divide
all_valid = True for clkfbout_mult in range(*self.clkfbout_mult_frange):
vco_freq = self.clkin_freq*clkfbout_mult all_valid = True
(vco_freq_min, vco_freq_max) = self.vco_freq_range vco_freq = self.clkin_freq*clkfbout_mult/divclk_divide
if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max: (vco_freq_min, vco_freq_max) = self.vco_freq_range
for n, (clk, f, p, m) in sorted(self.clkouts.items()): if (vco_freq >= vco_freq_min*(1 + self.vco_margin) and
valid = False vco_freq <= vco_freq_max*(1 - self.vco_margin)):
for d in range(*self.clkout_divide_range): for n, (clk, f, p, m) in sorted(self.clkouts.items()):
clk_freq = vco_freq/d valid = False
if abs(clk_freq - f) < f*m: for d in range(*self.clkout_divide_range):
config["clkout{}_freq".format(n)] = clk_freq clk_freq = vco_freq/d
config["clkout{}_divide".format(n)] = d if abs(clk_freq - f) < f*m:
config["clkout{}_phase".format(n)] = p config["clkout{}_freq".format(n)] = clk_freq
valid = True config["clkout{}_divide".format(n)] = d
break config["clkout{}_phase".format(n)] = p
if not valid: valid = True
all_valid = False break
else: if not valid:
all_valid = False all_valid = False
if all_valid: else:
config["vco"] = vco_freq all_valid = False
config["clkfbout_mult"] = clkfbout_mult if all_valid:
return config config["vco"] = vco_freq
config["clkfbout_mult"] = clkfbout_mult
return config
raise ValueError("No PLL config found") raise ValueError("No PLL config found")
def expose_drp(self): def expose_drp(self):
@ -122,6 +125,7 @@ class S7PLL(S7Clocking):
def __init__(self, speedgrade=-1): def __init__(self, speedgrade=-1):
S7Clocking.__init__(self) S7Clocking.__init__(self)
self.divclk_divide_range = (1, 56+1)
self.vco_freq_range = { self.vco_freq_range = {
-1: (800e6, 2133e6), -1: (800e6, 2133e6),
-2: (800e6, 1866e6), -2: (800e6, 1866e6),
@ -152,6 +156,7 @@ class S7MMCM(S7Clocking):
def __init__(self, speedgrade=-1): def __init__(self, speedgrade=-1):
S7Clocking.__init__(self) S7Clocking.__init__(self)
self.divclk_divide_range = (1, 106+1)
self.clkin_freq_range = { self.clkin_freq_range = {
-1: (10e6, 800e6), -1: (10e6, 800e6),
-2: (10e6, 933e6), -2: (10e6, 933e6),
@ -208,7 +213,8 @@ class USClocking(Module, AutoCSR):
clkfbout_mult_frange = (2, 64+1) clkfbout_mult_frange = (2, 64+1)
clkout_divide_range = (1, 128+1) clkout_divide_range = (1, 128+1)
def __init__(self): def __init__(self, vco_margin=0):
self.vco_margin = vco_margin
self.reset = Signal() self.reset = Signal()
self.locked = Signal() self.locked = Signal()
self.clkin_freq = None self.clkin_freq = None
@ -249,30 +255,32 @@ class USClocking(Module, AutoCSR):
def compute_config(self): def compute_config(self):
config = {} config = {}
config["divclk_divide"] = 1 for divclk_divide in range(*self.divclk_divide_range):
for clkfbout_mult in range(*self.clkfbout_mult_frange): config["divclk_divide"] = divclk_divide
all_valid = True for clkfbout_mult in range(*self.clkfbout_mult_frange):
vco_freq = self.clkin_freq*clkfbout_mult all_valid = True
(vco_freq_min, vco_freq_max) = self.vco_freq_range vco_freq = self.clkin_freq*clkfbout_mult/divclk_divide
if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max: (vco_freq_min, vco_freq_max) = self.vco_freq_range
for n, (clk, f, p, m) in sorted(self.clkouts.items()): if (vco_freq >= vco_freq_min*(1 + self.vco_margin) and
valid = False vco_freq <= vco_freq_max*(1 - self.vco_margin)):
for d in range(*self.clkout_divide_range): for n, (clk, f, p, m) in sorted(self.clkouts.items()):
clk_freq = vco_freq/d valid = False
if abs(clk_freq - f) < f*m: for d in range(*self.clkout_divide_range):
config["clkout{}_freq".format(n)] = clk_freq clk_freq = vco_freq/d
config["clkout{}_divide".format(n)] = d if abs(clk_freq - f) < f*m:
config["clkout{}_phase".format(n)] = p config["clkout{}_freq".format(n)] = clk_freq
valid = True config["clkout{}_divide".format(n)] = d
break config["clkout{}_phase".format(n)] = p
if not valid: valid = True
all_valid = False break
else: if not valid:
all_valid = False all_valid = False
if all_valid: else:
config["vco"] = vco_freq all_valid = False
config["clkfbout_mult"] = clkfbout_mult if all_valid:
return config config["vco"] = vco_freq
config["clkfbout_mult"] = clkfbout_mult
return config
raise ValueError("No PLL config found") raise ValueError("No PLL config found")
def expose_drp(self): def expose_drp(self):
@ -313,12 +321,12 @@ class USPLL(USClocking):
def __init__(self, speedgrade=-1): def __init__(self, speedgrade=-1):
USClocking.__init__(self) USClocking.__init__(self)
self.divclk_divide_range = (1, 56+1)
self.clkin_freq_range = { self.clkin_freq_range = {
-1: (70e6, 800e6), -1: (70e6, 800e6),
-2: (70e6, 933e6), -2: (70e6, 933e6),
-3: (70e6, 1066e6), -3: (70e6, 1066e6),
}[speedgrade] }[speedgrade]
self.vco_freq_range = { self.vco_freq_range = {
-1: (600e6, 1200e6), -1: (600e6, 1200e6),
-2: (600e6, 1335e6), -2: (600e6, 1335e6),
@ -349,12 +357,12 @@ class USMMCM(USClocking):
def __init__(self, speedgrade=-1): def __init__(self, speedgrade=-1):
USClocking.__init__(self) USClocking.__init__(self)
self.divclk_divide_range = (1, 106+1)
self.clkin_freq_range = { self.clkin_freq_range = {
-1: (10e6, 800e6), -1: (10e6, 800e6),
-2: (10e6, 933e6), -2: (10e6, 933e6),
-3: (10e6, 1066e6), -3: (10e6, 1066e6),
}[speedgrade] }[speedgrade]
self.vco_freq_range = { self.vco_freq_range = {
-1: (600e6, 1200e6), -1: (600e6, 1200e6),
-2: (600e6, 1440e6), -2: (600e6, 1440e6),