Commit dde94af2 authored by Andrey Filippov's avatar Andrey Filippov

Working on PLL/clocks configuration

parent 0876f70c
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2013, Elphel.inc.
# configuration of the SoC clocks
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
__author__ = "Andrey Filippov"
__copyright__ = "Copyright 2013, Elphel, Inc."
__license__ = "GPL"
__version__ = "3.0+"
__maintainer__ = "Andrey Filippov"
__email__ = "andrey@elphel.com"
__status__ = "Development"
import math
import ezynq_slcr_clk_def
import ezynq_registers
import ezynq_clkcfg_defs
import ezynq_feature_config
class EzynqClk:
def __init__(self,regs_masked,ddr_type,permit_undefined_bits=False,force=False,warn=False):
self.SLCR_CLK_DEFS= ezynq_slcr_clk_def.SLCR_CLK_DEFS
self.CLK_CFG_DEFS = ezynq_clkcfg_defs.CLK_CFG_DEFS
self.features=ezynq_feature_config.EzynqFeatures(self.CLK_CFG_DEFS,0) #CLK_CFG_DEFS
self.clk_register_set= ezynq_registers.EzynqRegisters(self.SLCR_CLK_DEFS,0,regs_masked,permit_undefined_bits)
if not ddr_type:
ddr_type = 'DDR3' # DDR3, DDR3L, DDR2, LPDDR2
self.ddr_type=ddr_type
self.pll_pars={}
for pll_line in ezynq_slcr_clk_def.PLL_PARS:
if isinstance(pll_line[0],tuple):
r=range(pll_line[0][0], pll_line[0][1]+1)
else:
r=[pll_line[0]]
for div in r:
self.pll_pars[div]={'PLL_CP':pll_line[1],'PLL_RES':pll_line[2],'LOCK_CNT':pll_line[3]}
# for f in self.pll_pars: print f, self.pll_pars[f]
def parse_parameters(self,raw_configs):
self.features.parse_features(raw_configs)
def check_missing_features(self):
self.features.check_missing_features()
def html_list_features(self,html_file):
if not html_file:
return
html_file.write('<h2>Clock configuration parameters</h2>\n')
self.features.html_list_features(html_file)
def calculate_dependent_pars(self):
speed_grade=self.features.get_par_value_or_default("SPEED_GRADE")
ddr_type=self.ddr_type
if not self.features.is_known('PLL_MAX_MHZ'): # ask permission
self.features.set_calculated_value('PLL_MAX_MHZ',
self.features.get_par_value_or_default('DS_PLL_MAX_%i_MHZ'%speed_grade), force=False)
if not self.features.is_known('ARM621_MAX_MHZ'): # ask permission
self.features.set_calculated_value('ARM621_MAX_MHZ',
self.features.get_par_value_or_default('DS_ARM621_MAX_%i_MHZ'%speed_grade), force=False)
if not self.features.is_known('ARM421_MAX_MHZ'): # ask permission
self.features.set_calculated_value('ARM421_MAX_MHZ',
self.features.get_par_value_or_default('DS_ARM421_MAX_%i_MHZ'%speed_grade), force=False)
if not self.features.is_known('DDR_3X_MAX_MHZ'): # ask permission
if ddr_type=='DDR3':
self.features.set_calculated_value('DDR_3X_MAX_MHZ',
0.5*self.features.get_par_value_or_default('DS_DDR3_MAX_%i_MBPS'%speed_grade), force=False)
else: # all other DDR types have the same DDR_3x timing for all speed grades
self.features.set_calculated_value('DDR_3X_MAX_MHZ',
0.5*self.features.get_par_value_or_default('DS_DDRX_MAX_X_MBPS'), force=False)
if not self.features.is_known('DDR_2X_MAX_MHZ'): # ask permission
self.features.set_calculated_value('DDR_2X_MAX_MHZ',
self.features.get_par_value_or_default('DS_DDR_2X_MAX_%i_MHZ'%speed_grade), force=False)
if not self.features.is_known('DDR2X_MHZ'):
self.features.set_calculated_value('DDR2X_MHZ', 2.0/3.0*self.features.get_par_value_or_default('DDR_MHZ'))
def check_ds_compliance(self):
self.is621=(0,1)[self.features.get_par_value_or_default('CPU_MODE')=='6_2_1']
self.compliance_margin=0.01*self.features.get_par_value_or_default('COMPLIANCE_PERCENT')
arm_max_mhz=(self.features.get_par_value_or_default('ARM421_MAX_MHZ'),self.features.get_par_value_or_default('ARM621_MAX_MHZ'))[self.is621]
self.arm6x4x=self.features.get_par_value_or_default('ARM_MHZ')
if self.arm6x4x > arm_max_mhz*(1+self.compliance_margin):
max_name=('ARM421_MAX_MHZ','ARM621_MAX_MHZ')[self.is621]
raise Exception ('Specified frequency for ARM clock (%s = %f) exceeds maximal (%s = %f) by more than %f%%'%(
self.features.get_par_confname('ARM_MHZ'),
self.features.get_par_value_or_default('ARM_MHZ'),
self.features.get_par_confname(max_name),
self.features.get_par_value_or_default(max_name),
self.features.get_par_value_or_default('COMPLIANCE_PERCENT')))
self.ddr_3x=self.features.get_par_value_or_default('DDR_MHZ')
if self.ddr_3x > self.features.get_par_value_or_default('DDR_3X_MAX_MHZ')*(1+self.compliance_margin):
raise Exception ('Specified frequency for DDR clock (%s = %f) exceeds maximal (%s = %f) by more than %f%%'%(
self.features.get_par_confname('DDR_MHZ'),
self.features.get_par_value_or_default('DDR_MHZ'),
self.features.get_par_confname('DDR_3X_MAX_MHZ'),
self.features.get_par_value_or_default('DDR_3X_MAX_MHZ'),
self.features.get_par_value_or_default('COMPLIANCE_PERCENT')))
self.ddr_2x=self.features.get_par_value_or_default('DDR2X_MHZ')
if self.ddr_2x > self.features.get_par_value_or_default('DDR_2X_MAX_MHZ')*(1+self.compliance_margin):
raise Exception ('Specified frequency for DDR_2X clock (%s = %f) exceeds maximal (%s = %f) by more than %f%%'%(
self.features.get_par_confname('DDR2X_MHZ'),
self.features.get_par_value_or_default('DDR2X_MHZ'),
self.features.get_par_confname('DDR_2X_MAX_MHZ'),
self.features.get_par_value_or_default('DDR_2X_MAX_MHZ'),
self.features.get_par_value_or_default('COMPLIANCE_PERCENT')))
# self.pll_pars[div]={'PLL_CP':pll_line[1],'PLL_RES':pll_line[2],'LOCK_CNT':pll_line[3]}
def get_valid_pll_fdiv(self): # common for all 3
f_in=self.features.get_par_value_or_default('PS_MHZ')
pll_min=self.features.get_par_value_or_default('PLL_MIN_MHZ')
pll_max=self.features.get_par_value_or_default('PLL_MAX_MHZ')
valid_fdiv=set()
for fdiv in self.pll_pars:
if (fdiv*f_in>=pll_min) and (fdiv*f_in<=pll_max) :
valid_fdiv.add(fdiv)
return valid_fdiv
def setup_clocks(self):
def pll_errors(valid_fdivs,valid_div6,f_in,f_target):
result={}
for fdiv in valid_fdivs:
freq_ratio=f_in*fdiv/f_target
best_log_err=None
for div6 in valid_div6:
log_err=abs(math.log(freq_ratio/div6))
if (best_log_err is None) or (log_err < best_log_err):
best_div6=div6
best_log_err=log_err
if not (best_log_err is None) :
result[fdiv]=(best_div6,best_log_err)
return result
def filter_best(fdiv_err):
best_error=None
for fdiv in fdiv_err:
if (best_error is None) or (fdiv_err[fdiv][1]<best_error):
best_error=fdiv_err[fdiv][1]
result = {}
for fdiv in fdiv_err:
if (fdiv_err[fdiv][1] == best_error):
result[fdiv]= fdiv_err[fdiv]
return result
def getBest(fdiv_err):
filtered=filter_best(fdiv_err)
lowest=None
for fdiv in filtered:
if (lowest is None) or (fdiv < lowest):
lowest=fdiv
return lowest
def filter_combine_multiclock(fdiv_errors):
combo_err={}
for fdiv in fdiv_errors[0]:
# verify it is available for all clocks
err=0
for fdiv_err in fdiv_errors:
if fdiv in fdiv_err:
err+=fdiv_err[fdiv][1]
else:
err=False
break
# for clock in fdiv_errors:
# if fdiv in fdiv_errors[clock]:
# err+=fdiv_errors[clock][1]
# else:
# err=False
# break
if not err is False:
combo_err[fdiv]=(fdiv_errors[0][fdiv][0],err)
return combo_err
self.f_in=self.features.get_par_value_or_default('PS_MHZ')
# so far all 2 PLLs have the same
arm_valid_fdiv=self.get_valid_pll_fdiv()
ddr_valid_fdiv=self.get_valid_pll_fdiv()
io_valid_fdiv=self.get_valid_pll_fdiv()
arm_valid_div6= [x for x in range (1,64) if (x != 1) and (x != 3)]
ddr_3x_valid_div6=[x for x in range (1,64) if (x & 1) ==0]
other_valid_div6= [x for x in range (1,64)]
# print arm_valid_fdiv
# arm_6x4x:
arm_target=self.features.get_par_value_or_default('ARM_MHZ')
pll_errs= pll_errors(arm_valid_fdiv,arm_valid_div6,self.f_in,arm_target)
# print 'pll_errs=',pll_errs
self.arm_pll_fdiv= getBest(pll_errs)
print 'getBest()->',self.arm_pll_fdiv
arm_pll_errs= filter_best(pll_errs)
print 'filtered pll_errs=',arm_pll_errs
self.arm_6x3x_div6=arm_pll_errs[self.arm_pll_fdiv][0]
# ddr
ddr_3x_target=self.features.get_par_value_or_default('DDR_MHZ')
ddr_2x_target=self.features.get_par_value_or_default('DDR2X_MHZ')
pll_errs_ddr_3x= pll_errors(ddr_valid_fdiv,ddr_3x_valid_div6,self.f_in,ddr_3x_target)
pll_errs_ddr_2x= pll_errors(ddr_valid_fdiv,other_valid_div6, self.f_in,ddr_2x_target)
# print 'pll_errs_ddr_3x=',pll_errs_ddr_3x
# print 'pll_errs_ddr_2x=',pll_errs_ddr_2x
ddr_combo_errors=filter_combine_multiclock((pll_errs_ddr_3x,pll_errs_ddr_2x))
# print 'ddr_combo_errors=',ddr_combo_errors
self.ddr_pll_fdiv= getBest(ddr_combo_errors)
self.ddr_3x_div6=pll_errs_ddr_3x[self.ddr_pll_fdiv][0]
self.ddr_2x_div6=pll_errs_ddr_2x[self.ddr_pll_fdiv][0]
print 'ddr_fdiv=',self.ddr_pll_fdiv,': pll_errs_ddr_3x=',pll_errs_ddr_3x[self.ddr_pll_fdiv],'pll_errs_ddr_2x=',pll_errs_ddr_2x[self.ddr_pll_fdiv]
self.features.set_calculated_value('ARM_MHZ', self.f_in*self.arm_pll_fdiv/self.arm_6x3x_div6, True)
self.features.set_calculated_value('DDR_MHZ', self.f_in*self.ddr_pll_fdiv/self.ddr_3x_div6, True)
self.features.set_calculated_value('DDR2X_MHZ',self.f_in*self.ddr_pll_fdiv/self.ddr_2x_div6, True)
def get_ddr_mhz(self):
return self.f_in*self.ddr_pll_fdiv/self.ddr_3x_div6
##### performance data, final values (overwrite calculated) #####
#CONFIG_EZYNQ_CLK_SPEED_GRADE = 2 # Device speed grade
#CONFIG_EZYNQ_CLK_PLL_MAX_MHZ = 1800.0 # Maximal PLL clock frequency, MHz. Overwrites default for selected speed grade: (Speed grade -1:1600, -2:1800, -3:2000)'},
#CONFIG_EZYNQ_CLK_PLL_MIN_MHZ = 780.0 # Minimal PLL clock frequency, all speed grades (MHz)'},
#CONFIG_EZYNQ_CLK_ARM621_MAX_MHZ = 733.0 # Maximal ARM clk_6x4x in 621 mode, MHz. Overwrites default for selected speed grade: (Speed grade -1:667, -2:733, -3:1000)'},
#CONFIG_EZYNQ_CLK_ARM421_MAX_MHZ = 600.0 # Maximal ARM clk_6x4x in 421 mode, MHz. Overwrites default for selected speed grade: (Speed grade -1:533, -2:600, -3:710)'},
#CONFIG_EZYNQ_CLK_DDR_3X_MAX_MHZ = 533.0 # Maximal DDR clk_3x clock frequency (MHz). Overwrites DDR-type/speed grade specific'},
#CONFIG_EZYNQ_CLK_DDR_2X_MAX_MHZ = 408.0 # Maximal DDR_2X clock frequency (MHz). Overwrites speed grade specific'},
##### datasheet data for specific speed grades #####
#CONFIG_EZYNQ_CLK_DS_PLL_MAX_1_MHZ = 1600.0 # Maximal PLL clock frequency for speed grade 1 (MHz)'},
#CONFIG_EZYNQ_CLK_DS_PLL_MAX_2_MHZ = 1800.0 # Maximal PLL clock frequency for speed grade 2 (MHz)'},
#CONFIG_EZYNQ_CLK_DS_PLL_MAX_3_MHZ = 2000.0 # Maximal PLL clock frequency for speed grade 3 (MHz)'},
#CONFIG_EZYNQ_CLK_DS_ARM621_MAX_1_MHZ = 667.0 # Maximal ARM clk_6x4x in 621 mode for speed grade 1, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM621_MAX_2_MHZ = 733.0 #Maximal ARM clk_6x4x in 621 mode for speed grade 2, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM621_MAX_3_MHZ =1000.0 #Maximal ARM clk_6x4x in 621 mode for speed grade 3, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM421_MAX_1_MHZ = 533.0 # Maximal ARM clk_6x4x in 421 mode for speed grade 1, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM421_MAX_2_MHZ = 600.0 # Maximal ARM clk_6x4x in 421 mode for speed grade 2, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM421_MAX_3_MHZ = 710.0 # Maximal ARM clk_6x4x in 421 mode for speed grade 3, MHz'},
#CONFIG_EZYNQ_CLK_DS_DDR3_MAX_1_MBPS = 1066.0 # Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 1'},
#CONFIG_EZYNQ_CLK_DS_DDR3_MAX_2_MBPS = 1066.0 # Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 2'},
#CONFIG_EZYNQ_CLK_DS_DDR3_MAX_3_MBPS = 1333.0 # Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 3'},
#CONFIG_EZYNQ_CLK_DS_DDRX_MAX_X_MBPS = 800.0 # Maximal DDR3L, DDR2, LPDDR2 performance in Mb/s - twice clock frequency (MHz). All speed grades'},
#CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_1_MHZ = 355.0 # Maximal DDR_2X clock frequency (MHz) for speed grade 1'},
#CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_2_MHZ = 408.0 # Maximal DDR_2X clock frequency (MHz) for speed grade 2'},
#CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_3_MHZ = 444.0 # Maximal DDR_2X clock frequency (MHz) for speed grade 3'},
pass
# def get_par_value_or_default(name):
############# Main clock settings #############
#CONFIG_EZYNQ_CLK_PS_MHZ = 33.333333 # PS_CLK System clock input frequency (MHz)
#CONFIG_EZYNQ_CLK_DDR_MHZ = 533.333333 # DDR clock frequency - DDR_3X (MHz)
#CONFIG_EZYNQ_CLK_ARM_MHZ = 667 # ARM CPU clock frequency cpu_6x4x (MHz)
#CONFIG_EZYNQ_CLK_CPU_MODE = 6_2_1 # CPU clocks set 6:2:1 (6:3:2:1) or 4:2:1 (4:2:2:1)
############# Normally do not need to be modified #############
#CONFIG_EZYNQ_CLK_DDR_DCI_MHZ = 10.0 # DDR DCI clock frequency (MHz). Normally 10 Mhz'},
#CONFIG_EZYNQ_CLK_DDR2X_MHZ = 355.556 # DDR2X clock frequency (MHz). Does not need to be exactly 2/3 of DDR3X clock'},
#CONFIG_EZYNQ_CLK_DDR_DCI_MHZ= 10.0 # DDR DCI clock frequency (MHz). Normally 10Mhz
#CONFIG_EZYNQ_CLK_SMC_MHZ = 100.0 # Static memory controller clock frequency (MHz). Normally 100 Mhz
#CONFIG_EZYNQ_CLK_QSPI_MHZ = 200.0 # Quad SPI memory controller clock frequency (MHz). Normally 200 Mhz
#CONFIG_EZYNQ_CLK_GIGE_MHZ = 125.0 # GigE Ethernet controller reference clock frequency (MHz). Normally 125 Mhz
#CONFIG_EZYNQ_CLK_SDIO_MHZ = 100.0 # SDIO controller reference clock frequency (MHz). Normally 100 Mhz
#CONFIG_EZYNQ_CLK_UART_MHZ = 25.0 # UART controller reference clock frequency (MHz). Normally 25 Mhz
#CONFIG_EZYNQ_CLK_SPI_MHZ = 200.0 # SPI controller reference clock frequency (MHz). Normally 200 Mhz
#CONFIG_EZYNQ_CLK_CAN_MHZ = 100.0 # CAN controller reference clock frequency (MHz). Normally 100 Mhz
#CONFIG_EZYNQ_CLK_PCAP_MHZ = 200.0 # PCAP clock frequency (MHz). Normally 200 Mhz
#CONFIG_EZYNQ_CLK_TRACE_MHZ = 100.0 # Trace Port clock frequency (MHz). Normally 100 Mhz
#CONFIG_EZYNQ_CLK_PLL_FCLK_MHZ = 50.0 # PLL DCLK clock frequency (MHz). Normally 50 Mhz
#CONFIG_EZYNQ_CLK_ARM_SRC = ARM # ARM CPU clock source (normally ARM PLL)'},
#CONFIG_EZYNQ_CLK_DDR_SRC = DDR # DDR (DDR2x, DDR3x) clock source (normally DDR PLL)'},
#CONFIG_EZYNQ_CLK_DCI_SRC = DDR # DDR DCI clock source (normally DDR PLL)'},
#CONFIG_EZYNQ_CLK_SMC_SRC = IO # Static memory controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_QSPI_SRC = IO # Quad SPI memory controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_GIGE_SRC = IO # GigE Ethernet controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_SDIO_SRC = IO # SDIO controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_UART_SRC = IO # UART controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_SPI_SRC = IO # SPI controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_CAN_SRC = IO # CAN controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_PCAP_SRC = IO # PCAP controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_TRACE_SRC = IO # Trace Port clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_PLL_FCLK_SRC = IO # PLL FCLK clock source (normally IO PLL)'},
#!/usr/bin/env python
# Copyright (C) 2013, Elphel.inc.
# Definitions of configuration parameters for clocks
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
__author__ = "Andrey Filippov"
__copyright__ = "Copyright 2013, Elphel, Inc."
__license__ = "GPL"
__version__ = "3.0+"
__maintainer__ = "Andrey Filippov"
__email__ = "andrey@elphel.com"
__status__ = "Development"
#Use 'TYPE':'I' for decimal output, 'H' - for hex. On input both are accepted
CLK_CFG_DEFS=[
{'NAME':'PS_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_PS_MHZ','TYPE':'F','MANDATORY':True, 'DERIVED':False,'DEFAULT':33.333333,
'DESCRIPTION':'PS_CLK System clock input frequency (MHz)'},
{'NAME':'DDR_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DDR_MHZ','TYPE':'F','MANDATORY':True, 'DERIVED':False,'DEFAULT':533.333333,
'DESCRIPTION':'DDR clock frequency - DDR_3X (MHz)'},
{'NAME':'ARM_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_ARM_MHZ','TYPE':'F','MANDATORY':True,'DERIVED':False,'DEFAULT':667.0,
'DESCRIPTION':'ARM CPU clock frequency cpu_6x4x (MHz)'},
{'NAME':'CPU_MODE', 'CONF_NAME':'CONFIG_EZYNQ_CLK_CPU_MODE','TYPE':('6_2_1','4_2_1'),'MANDATORY':True,'DERIVED':False,'DEFAULT':'6_2_1',
'DESCRIPTION':'CPU clocks set 6:2:1 (6:3:2:1) or 4:2:1 (4:2:2:1)'},
{'NAME':'DDR2X_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DDR2X_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':355.556,
'DESCRIPTION':'DDR_2X clock frequency (MHz). Does not need to be exactly 2/3 of DDR_3X clock'},
{'NAME':'DDR_DCI_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DDR_DCI_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':10.0,
'DESCRIPTION':'DDR DCI clock frequency (MHz). Normally 10 Mhz'},
{'NAME':'SMC_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_SMC_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':100.0,
'DESCRIPTION':'Static memory controller clock frequency (MHz). Normally 100 Mhz'},
{'NAME':'QSPI_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_QSPI_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':200.0,
'DESCRIPTION':'Quad SPI memory controller clock frequency (MHz). Normally 200 Mhz'},
{'NAME':'GIGE_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_GIGE_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':125.0,
'DESCRIPTION':'GigE Ethernet controller reference clock frequency (MHz). Normally 125 Mhz'},
{'NAME':'SDIO_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_SDIO_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':100.0,
'DESCRIPTION':'SDIO controller reference clock frequency (MHz). Normally 100 Mhz'},
{'NAME':'UART_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_UART_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':25.0,
'DESCRIPTION':'UART controller reference clock frequency (MHz). Normally 25 Mhz'},
{'NAME':'SPI_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_SPI_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':200.0,
'DESCRIPTION':'SPI controller reference clock frequency (MHz). Normally 200 Mhz'},
{'NAME':'CAN_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_CAN_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':100.0,
'DESCRIPTION':'CAN controller reference clock frequency (MHz). Normally 100 Mhz'},
{'NAME':'PCAP_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_PCAP_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':200.0,
'DESCRIPTION':'PCAP clock frequency (MHz). Normally 200 Mhz'},
{'NAME':'TRACE_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_TRACE_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':100.0,
'DESCRIPTION':'Trace Port clock frequency (MHz). Normally 100 Mhz'},
{'NAME':'PLL_FCLK_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_PLL_FCLK_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':50.0,
'DESCRIPTION':'PLL FCLK clock frequency (MHz). Normally 50 Mhz'},
{'NAME':'ARM_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_ARM_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'ARM',
'DESCRIPTION':'ARM CPU clock source (normally ARM PLL)'},
{'NAME':'DDR_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DDR_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'DDR',
'DESCRIPTION':'DDR (DDR2x, DDR3x) clock source (normally DDR PLL)'},
{'NAME':'DCI_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DCI_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'DDR',
'DESCRIPTION':'DDR DCI clock source (normally DDR PLL)'},
{'NAME':'SMC_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_SMC_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'Static memory controller clock source (normally IO PLL)'},
{'NAME':'QSPI_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_QSPI_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'Quad SPI memory controller clock source (normally IO PLL)'},
{'NAME':'GIGE_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_GIGE_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'GigE Ethernet controller clock source (normally IO PLL)'},
{'NAME':'SDIO_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_SDIO_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'SDIO controller clock source (normally IO PLL)'},
{'NAME':'UART_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_UART_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'UART controller clock source (normally IO PLL)'},
{'NAME':'SPI_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_SPI_SRC', 'TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'SPI controller clock source (normally IO PLL)'},
{'NAME':'CAM_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_CAN_SRC', 'TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'CAN controller clock source (normally IO PLL)'},
{'NAME':'PCAP_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_PCAP_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'PCAP controller clock source (normally IO PLL)'},
{'NAME':'TRACE_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_TRACE_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'Trace Port clock source (normally IO PLL)'},
{'NAME':'PLL_FCLK_SRC', 'CONF_NAME':'CONFIG_EZYNQ_CLK_PLL_FCLK_SRC','TYPE':('ARM','DDR','IO'),'MANDATORY':False,'DERIVED':False,'DEFAULT':'IO',
'DESCRIPTION':'PLL FCLK clock source (normally IO PLL)'},
# performance data, final values (overwrites calculated)
{'NAME':'SPEED_GRADE', 'CONF_NAME':'CONFIG_EZYNQ_CLK_SPEED_GRADE','TYPE':(1,2,3),'MANDATORY':False,'DERIVED':False,'DEFAULT':2,
'DESCRIPTION':'Device speed grade'},
{'NAME':'PLL_MAX_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_PLL_MAX_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':1800.0,
'DESCRIPTION':'Maximal PLL clock frequency, MHz. Overwrites default for selected speed grade: (Speed grade -1:1600, -2:1800, -3:2000)'},
{'NAME':'PLL_MIN_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_PLL_MIN_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':780.0,
'DESCRIPTION':'Minimal PLL clock frequency, all speed grades (MHz)'},
{'NAME':'ARM621_MAX_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_ARM621_MAX_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':733.0,
'DESCRIPTION':'Maximal ARM clk_6x4x in 621 mode, MHz. Overwrites default for selected speed grade: (Speed grade -1:667, -2:733, -3:1000)'},
{'NAME':'ARM421_MAX_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_ARM421_MAX_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':600.0,
'DESCRIPTION':'Maximal ARM clk_6x4x in 421 mode, MHz. Overwrites default for selected speed grade: (Speed grade -1:533, -2:600, -3:710)'},
{'NAME':'DDR_3X_MAX_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DDR_3X_MAX_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':533.0,
'DESCRIPTION':'Maximal DDR clk_3x clock frequency (MHz). Overwrites DDR-type/speed grade specific'},
{'NAME':'DDR_2X_MAX_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DDR_2X_MAX_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':408.0,
'DESCRIPTION':'Maximal DDR_2X clock frequency (MHz). Overwrites speed grade specific'},
# performance data, datasheet values
{'NAME':'DS_PLL_MAX_1_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DS_PLL_MAX_1_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':1600.0,
'DESCRIPTION':'Maximal PLL clock frequency for speed grade 1 (MHz)'},
{'NAME':'DS_PLL_MAX_2_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DS_PLL_MAX_2_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':1800.0,
'DESCRIPTION':'Maximal PLL clock frequency for speed grade 2 (MHz)'},
{'NAME':'DS_PLL_MAX_3_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DS_PLL_MAX_3_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':2000.0,
'DESCRIPTION':'Maximal PLL clock frequency for speed grade 3 (MHz)'},
{'NAME':'DS_ARM621_MAX_1_MHZ','CONF_NAME':'CONFIG_EZYNQ_CLK_DS_ARM621_MAX_1_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':667.0,
'DESCRIPTION':'Maximal ARM clk_6x4x in 621 mode for speed grade 1, MHz'},
{'NAME':'DS_ARM621_MAX_2_MHZ','CONF_NAME':'CONFIG_EZYNQ_CLK_DS_ARM621_MAX_2_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':733.0,
'DESCRIPTION':'Maximal ARM clk_6x4x in 621 mode for speed grade 2, MHz'},
{'NAME':'DS_ARM621_MAX_3_MHZ','CONF_NAME':'CONFIG_EZYNQ_CLK_DS_ARM621_MAX_3_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':1000.0,
'DESCRIPTION':'Maximal ARM clk_6x4x in 621 mode for speed grade 3, MHz'},
{'NAME':'DS_ARM421_MAX_1_MHZ','CONF_NAME':'CONFIG_EZYNQ_CLK_DS_ARM421_MAX_1_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':533.0,
'DESCRIPTION':'Maximal ARM clk_6x4x in 421 mode for speed grade 1, MHz'},
{'NAME':'DS_ARM421_MAX_2_MHZ','CONF_NAME':'CONFIG_EZYNQ_CLK_DS_ARM421_MAX_2_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':600.0,
'DESCRIPTION':'Maximal ARM clk_6x4x in 421 mode for speed grade 2, MHz'},
{'NAME':'DS_ARM421_MAX_3_MHZ','CONF_NAME':'CONFIG_EZYNQ_CLK_DS_ARM421_MAX_3_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':710.0,
'DESCRIPTION':'Maximal ARM clk_6x4x in 421 mode for speed grade 3, MHz'},
{'NAME':'DS_DDR3_MAX_1_MBPS', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DS_DDR3_MAX_1_MBPS','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':1066.0,
'DESCRIPTION':'Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 1'},
{'NAME':'DS_DDR3_MAX_2_MBPS', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DS_DDR3_MAX_2_MBPS','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':1066.0,
'DESCRIPTION':'Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 2'},
{'NAME':'DS_DDR3_MAX_3_MBPS', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DS_DDR3_MAX_3_MBPS','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':1333.0,
'DESCRIPTION':'Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 3'},
{'NAME':'DS_DDRX_MAX_X_MBPS', 'CONF_NAME':'CONFIG_EZYNQ_CLK_DS_DDRX_MAX_X_MBPS','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':800.0,
'DESCRIPTION':'Maximal DDR3L, DDR2, LPDDR2 performance in Mb/s - twice clock frequency (MHz). All speed grades'},
{'NAME':'DS_DDR_2X_MAX_1_MHZ','CONF_NAME':'CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_1_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':355.0,
'DESCRIPTION':'Maximal DDR_2X clock frequency (MHz) for speed grade 1'},
{'NAME':'DS_DDR_2X_MAX_2_MHZ','CONF_NAME':'CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_2_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':408.0,
'DESCRIPTION':'Maximal DDR_2X clock frequency (MHz) for speed grade 2'},
{'NAME':'DS_DDR_2X_MAX_3_MHZ','CONF_NAME':'CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_3_MHZ','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':444.0,
'DESCRIPTION':'Maximal DDR_2X clock frequency (MHz) for speed grade 3'},
{'NAME':'COMPLIANCE_PERCENT','CONF_NAME':'CONFIG_EZYNQ_CLK_COMPLIANCE_PERCENT','TYPE':'F','MANDATORY':False,'DERIVED':False,'DEFAULT':5.0,
'DESCRIPTION':'Allow exceeding maximal limits by this margin (percent'},
]
############# Main clock settings #############
#CONFIG_EZYNQ_CLK_PS_MHZ = 33.333333 # PS_CLK System clock input frequency (MHz)
#CONFIG_EZYNQ_CLK_DDR_MHZ = 533.333333 # DDR clock frequency - DDR_3X (MHz)
#CONFIG_EZYNQ_CLK_ARM_MHZ = 667 # ARM CPU clock frequency cpu_6x4x (MHz)
#CONFIG_EZYNQ_CLK_CPU_MODE = 6_2_1 # CPU clocks set 6:2:1 (6:3:2:1) or 4:2:1 (4:2:2:1)
############# Normally do not need to be modified #############
#CONFIG_EZYNQ_CLK_DDR_DCI_MHZ = 10.0 # DDR DCI clock frequency (MHz). Normally 10 Mhz'},
#CONFIG_EZYNQ_CLK_DDR2X_MHZ = 355.556 # DDR2X clock frequency (MHz). Does not need to be exactly 2/3 of DDR3X clock'},
#CONFIG_EZYNQ_CLK_DDR_DCI_MHZ= 10.0 # DDR DCI clock frequency (MHz). Normally 10Mhz
#CONFIG_EZYNQ_CLK_SMC_MHZ = 100.0 # Static memory controller clock frequency (MHz). Normally 100 Mhz
#CONFIG_EZYNQ_CLK_QSPI_MHZ = 200.0 # Quad SPI memory controller clock frequency (MHz). Normally 200 Mhz
#CONFIG_EZYNQ_CLK_GIGE_MHZ = 125.0 # GigE Ethernet controller reference clock frequency (MHz). Normally 125 Mhz
#CONFIG_EZYNQ_CLK_SDIO_MHZ = 100.0 # SDIO controller reference clock frequency (MHz). Normally 100 Mhz
#CONFIG_EZYNQ_CLK_UART_MHZ = 25.0 # UART controller reference clock frequency (MHz). Normally 25 Mhz
#CONFIG_EZYNQ_CLK_SPI_MHZ = 200.0 # SPI controller reference clock frequency (MHz). Normally 200 Mhz
#CONFIG_EZYNQ_CLK_CAN_MHZ = 100.0 # CAN controller reference clock frequency (MHz). Normally 100 Mhz
#CONFIG_EZYNQ_CLK_PCAP_MHZ = 200.0 # PCAP clock frequency (MHz). Normally 200 Mhz
#CONFIG_EZYNQ_CLK_TRACE_MHZ = 100.0 # Trace Port clock frequency (MHz). Normally 100 Mhz
#CONFIG_EZYNQ_CLK_PLL_FCLK_MHZ = 50.0 # PLL DCLK clock frequency (MHz). Normally 50 Mhz
#CONFIG_EZYNQ_CLK_ARM_SRC = ARM # ARM CPU clock source (normally ARM PLL)'},
#CONFIG_EZYNQ_CLK_DDR_SRC = DDR # DDR (DDR2x, DDR3x) clock source (normally DDR PLL)'},
#CONFIG_EZYNQ_CLK_DCI_SRC = DDR # DDR DCI clock source (normally DDR PLL)'},
#CONFIG_EZYNQ_CLK_SMC_SRC = IO # Static memory controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_QSPI_SRC = IO # Quad SPI memory controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_GIGE_SRC = IO # GigE Ethernet controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_SDIO_SRC = IO # SDIO controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_UART_SRC = IO # UART controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_SPI_SRC = IO # SPI controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_CAN_SRC = IO # CAN controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_PCAP_SRC = IO # PCAP controller clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_TRACE_SRC = IO # Trace Port clock source (normally IO PLL)'},
#CONFIG_EZYNQ_CLK_PLL_FCLK_SRC = IO # PLL FCLK clock source (normally IO PLL)'},
##### performance data, final values (overwrite calculated) #####
#CONFIG_EZYNQ_CLK_SPEED_GRADE = 2 # Device speed grade
#CONFIG_EZYNQ_CLK_PLL_MAX_MHZ = 1800.0 # Maximal PLL clock frequency, MHz. Overwrites default for selected speed grade: (Speed grade -1:1600, -2:1800, -3:2000)'},
#CONFIG_EZYNQ_CLK_PLL_MIN_MHZ = 780.0 # Minimal PLL clock frequency, all speed grades (MHz)'},
#CONFIG_EZYNQ_CLK_ARM621_MAX_MHZ = 733.0 # Maximal ARM clk_6x4x in 621 mode, MHz. Overwrites default for selected speed grade: (Speed grade -1:667, -2:733, -3:1000)'},
#CONFIG_EZYNQ_CLK_ARM421_MAX_MHZ = 600.0 # Maximal ARM clk_6x4x in 421 mode, MHz. Overwrites default for selected speed grade: (Speed grade -1:533, -2:600, -3:710)'},
#CONFIG_EZYNQ_CLK_DDR_3X_MAX_MHZ = 533.0 # Maximal DDR clk_3x clock frequency (MHz). Overwrites DDR-type/speed grade specific'},
#CONFIG_EZYNQ_CLK_DDR_2X_MAX_MHZ = 408.0 # Maximal DDR_2X clock frequency (MHz). Overwrites speed grade specific'},
##### datasheet data for specific speed grades #####
#CONFIG_EZYNQ_CLK_DS_PLL_MAX_1_MHZ = 1600.0 # Maximal PLL clock frequency for speed grade 1 (MHz)'},
#CONFIG_EZYNQ_CLK_DS_PLL_MAX_2_MHZ = 1800.0 # Maximal PLL clock frequency for speed grade 2 (MHz)'},
#CONFIG_EZYNQ_CLK_DS_PLL_MAX_3_MHZ = 2000.0 # Maximal PLL clock frequency for speed grade 3 (MHz)'},
#CONFIG_EZYNQ_CLK_DS_ARM621_MAX_1_MHZ = 667.0 # Maximal ARM clk_6x4x in 621 mode for speed grade 1, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM621_MAX_2_MHZ = 733.0 #Maximal ARM clk_6x4x in 621 mode for speed grade 2, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM621_MAX_3_MHZ =1000.0 #Maximal ARM clk_6x4x in 621 mode for speed grade 3, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM421_MAX_1_MHZ = 533.0 # Maximal ARM clk_6x4x in 421 mode for speed grade 1, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM421_MAX_2_MHZ = 600.0 # Maximal ARM clk_6x4x in 421 mode for speed grade 2, MHz'},
#CONFIG_EZYNQ_CLK_DS_ARM421_MAX_3_MHZ = 710.0 # Maximal ARM clk_6x4x in 421 mode for speed grade 3, MHz'},
#CONFIG_EZYNQ_CLK_DS_DDR3_MAX_1_MBPS = 1066.0 # Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 1'},
#CONFIG_EZYNQ_CLK_DS_DDR3_MAX_2_MBPS = 1066.0 # Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 2'},
#CONFIG_EZYNQ_CLK_DS_DDR3_MAX_3_MBPS = 1333.0 # Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 3'},
#CONFIG_EZYNQ_CLK_DS_DDRX_MAX_X_MBPS = 800.0 # Maximal DDR3L, DDR2, LPDDR2 performance in Mb/s - twice clock frequency (MHz). All speed grades'},
#CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_1_MHZ = 355.0 # Maximal DDR_2X clock frequency (MHz) for speed grade 1'},
#CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_2_MHZ = 408.0 # Maximal DDR_2X clock frequency (MHz) for speed grade 2'},
#CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_3_MHZ = 444.0 # Maximal DDR_2X clock frequency (MHz) for speed grade 3'},
#CONFIG_EZYNQ_CLK_COMPLIANCE_PERCENT = 5.0 # Allow exceeding maximal limits by this margin (percent'},
......@@ -41,22 +41,6 @@ class EzynqDDR:
self.DDRC_DEFS= ezynq_ddrc_defs.DDRC_DEFS
self.DDRIOB_DEFS=ezynq_ddriob_def.DDRIOB_DEFS
self.DDR_CFG_DEFS=ezynq_ddrcfg_defs.DDR_CFG_DEFS
# self.ddrc_register_sets= {'PRE': ezynq_registers.EzynqRegisters(self.DDRC_DEFS,0,regs_masked,permit_undefined_bits), # all now start from the same registers
# 'MAIN':ezynq_registers.EzynqRegisters(self.DDRC_DEFS,0,regs_masked,permit_undefined_bits),
# 'POST':ezynq_registers.EzynqRegisters(self.DDRC_DEFS,0,regs_masked,permit_undefined_bits)}
# self.ddriob_register_sets= {'PRE': ezynq_registers.EzynqRegisters(self.DDRIOB_DEFS,0,regs_masked,permit_undefined_bits), # all now start from the same registers
# 'MAIN':ezynq_registers.EzynqRegisters(self.DDRIOB_DEFS,0,regs_masked,permit_undefined_bits),
# 'POST':ezynq_registers.EzynqRegisters(self.DDRIOB_DEFS,0,regs_masked,permit_undefined_bits)}
# self.set_ddrc_attribs=(
# {'NAME':'PRE','POSTFIX':'_PRE','PREFIX':'CONFIG_EZYNQ_DDR_SETREG_','TITLE':"DDR Controller Register Pre-Set"},
# {'NAME':'MAIN','POSTFIX':'','PREFIX':'CONFIG_EZYNQ_DDR_SETREG_','TITLE':"DDR Controller Register Set"},
# {'NAME':'POST','POSTFIX':'_POST','PREFIX':'CONFIG_EZYNQ_DDR_SETREG_','TITLE':"DDR Controller Register Post-Set"})
# self.set_ddiob_attribs=(
# {'NAME':'PRE','POSTFIX':'_PRE','PREFIX':'CONFIG_EZYNQ_DDRIOB_SETREG_','TITLE':"DDR I/O Buffer Register Pre-Set"},
# {'NAME':'MAIN','POSTFIX':'','PREFIX':'CONFIG_EZYNQ_DDRIOB_SETREG_','TITLE':"DDR I/O Buffer Register Set"},
# {'NAME':'POST','POSTFIX':'_POST','PREFIX':'CONFIG_EZYNQ_DDRIOB_SETREG_','TITLE':"DDR I/O Buffer Register Post-Set"})
# self.postfixes=[attrib['POSTFIX'] for attrib in self.set_ddrc_attribs]
self.features=ezynq_feature_config.EzynqFeatures(self.DDR_CFG_DEFS,0) #DDR_CFG_DEFS
self.ddrc_register_set= ezynq_registers.EzynqRegisters(self.DDRC_DEFS,0,regs_masked,permit_undefined_bits)
self.ddriob_register_set=ezynq_registers.EzynqRegisters(self.DDRIOB_DEFS,0,regs_masked,permit_undefined_bits)
......@@ -71,8 +55,11 @@ class EzynqDDR:
return
html_file.write('<h2>DDR memory configuration parameters</h2>\n')
self.features.html_list_features(html_file)
def calculate_dependent_pars(self):
def calculate_dependent_pars(self,ddr_mhz):
#TODO: just testing on a few pars, migrate more of them
if not self.features.is_known('FREQ_MHZ'):
self.features.set_calculated_value('FREQ_MHZ',ddr_mhz,True)
try:
tCK=1000.0/self.features.get_par_value('FREQ_MHZ')
# print 'FREQ_MHZ=',self.features.get_par_value('FREQ_MHZ')
......@@ -258,6 +245,9 @@ class EzynqDDR:
def get_new_register_sets(self):
# return self.ddrc_register_sets['MAIN'].get_register_sets(True,True)
return self.ddrc_register_set.get_register_sets(True,True)
def get_ddr_type(self):
return self.features.get_par_value('MEMORY_TYPE')
def ddr_init_memory(self,current_reg_sets,force=False,warn=False):
# print 'ddr_init_memory, len(current_reg_sets)=',len(current_reg_sets),'\n'
......
......@@ -25,10 +25,8 @@ __status__ = "Development"
DDR_CFG_DEFS=[
{'NAME':'ENABLE', 'CONF_NAME':'CONFIG_EZYNQ_DDR_ENABLE','TYPE':'B','MANDATORY':True,'DERIVED':False,'DEFAULT':True,
'DESCRIPTION':'Enable DDR memory'},
{'NAME':'TARGET_FREQ_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_DDR_TARGET_FREQ_MHZ','TYPE':'F','MANDATORY':True,'DERIVED':True,'DEFAULT':533.333333,
'DESCRIPTION':'Target DDR clock frequency in MHz (actual frequency will depend on the clock/clock muxes)'},
{'NAME':'FREQ_MHZ', 'CONF_NAME':'CONFIG_EZYNQ_DDR_FREQ_MHZ','TYPE':'F','MANDATORY':True,'DERIVED':True,'DEFAULT':533.333333,
'DESCRIPTION':'Actual DDR clock frequency in MHz, may be derived form CONFIG_EZYNQ_DDR_TARGET_FREQ_MHZ and clock multiplexer settings'},
'DESCRIPTION':'DDR clock frequency in MHz, this value overwrites the one calculated by the PLL/clock setup'},
{'NAME':'BANK_ADDR_MAP', 'CONF_NAME':'CONFIG_EZYNQ_DDR_BANK_ADDR_MAP','TYPE':'I','MANDATORY':True,'DERIVED':False,'DEFAULT':10,
'DESCRIPTION':'DRAM address mapping: number of combined column and row addresses lower than BA0'},
{'NAME':'ARB_PAGE_BANK', 'CONF_NAME':'CONFIG_EZYNQ_DDR_ARB_PAGE_BANK','TYPE':'B','MANDATORY':False,'DERIVED':False,'DEFAULT':False,
......@@ -210,7 +208,8 @@ DDR_CFG_DEFS=[
#TODO make some of (possibly) derived, leave '_T_' for ns only!
# CONFIG_EZYNQ_DDR_FREQ_MHZ = 533.333333 *
# CONFIG_EZYNQ_DDR_FREQ_MHZ = 533.333333 # DDR clock frequency in MHz, this value overwrites the one calculated by the PLL/clock setup
# CONFIG_EZYNQ_DDR_CL = 7 *
# CONFIG_EZYNQ_DDR_CWL = 6 *
# CONFIG_EZYNQ_DDR_DS_RCD = 7 (was CONFIG_EZYNQ_DDR_DS_T_RCD = 7) *
......
......@@ -74,6 +74,7 @@ class EzynqFeatures:
self.defs[feature['NAME']]['INDEX']=i
self.channel=channel
self.pars={}
self.target={} # target values (as specified)
self.config_names={}
self.defined=set()
self.calculated=set()
......@@ -130,6 +131,7 @@ class EzynqFeatures:
pass #keep string value
self.pars[name]=value
self.defined.add(name)
self.target[name]=value
#check after calculating derivative parameters
def check_missing_features(self):
all_set=True
......@@ -173,6 +175,32 @@ class EzynqFeatures:
except:
raise Exception (name+' not found in self.defs') # should not happen with wrong data, program bug
raise Exception (config_name+' is not defined, nor calculated')
def get_par_value_or_default(self,name):
try:
return self.pars[name]
except:
# print 'name=',name
# print self.pars
try:
config_name=self.defs[name]['CONF_NAME']
except:
raise Exception (name+' not found in self.defs') # should not happen with wrong data, program bug
try:
return self.defs[name]['DEFAULT']
except:
raise Exception (config_name+' is not defined, nor calculated and no default is provided')
def get_par_target(self,name):
try:
return self.target[name]
except:
try:
config_name=self.defs[name]['CONF_NAME']
except:
raise Exception (name+' not found in self.defs') # should not happen with wrong data, program bug
raise Exception ('Target value for '+config_name+' is not defined')
def is_known(self,name): # specified or calculated
return (name in self.defined) or (name in self.calculated)
......@@ -209,7 +237,8 @@ class EzynqFeatures:
if not html_file:
return
html_file.write('<table border="1">\n')
html_file.write('<tr><th>Configuration name</th><th>Value</th><th>Type/<br/>Choices</th><th>Mandatory</th><th>Origin</th><th>Default</th><th>Description</th></tr>\n')
# html_file.write('<tr><th>Configuration name</th><th>Value<br/>(Target)</th><th>Type/<br/>Choices</th><th>Mandatory</th><th>Origin</th><th>Default</th><th>Description</th></tr>\n')
html_file.write('<tr><th>Configuration name</th><th>Value (Target)</th><th>Type/<br/>Choices</th><th>Mandatory</th><th>Origin</th><th>Default</th><th>Description</th></tr>\n')
# print self.get_par_names()
# for name in self.pars:
for name in self.get_par_names():
......@@ -221,13 +250,24 @@ class EzynqFeatures:
value=hex(value)
else:
value=str(value)
try:
target_value=self.get_par_target(name)
if isinstance(target_value,int):
if (feature['TYPE']=='H'):
target_value=hex(target_value)
else:
target_value=str(target_value)
if value != target_value: # Do not show target_value if it is the same as actual
# value+='<br/>('+str(target_value)+')'
value='<b>'+str(value)+'</b> ('+str(target_value)+')'
except: # target_value is not set
pass
if name in self.defined:
origin="Defined"
elif name in self.calculated:
origin="Calculated"
else:
origin="Default"
if isinstance (feature['TYPE'],tuple):
par_type='<select>\n'
for t in feature['TYPE']:
......
......@@ -22,11 +22,12 @@ __maintainer__ = "Andrey Filippov"
__email__ = "andrey@elphel.com"
__status__ = "Development"
import struct
import argparse # http://docs.python.org/2/howto/argparse.html
import ezynq_ddr
import ezynq_registers
import ezynq_mio
# http://docs.python.org/2/howto/argparse.html
import argparse
import ezynq_clk
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbosity', action='count', help='increase output verbosity')
parser.add_argument('-c', '--configs', help='Configuration file (such as autoconf.mk)')
......@@ -289,6 +290,18 @@ mio_regs.process_mio(raw_configs,WARN) # does not use regs_masked
ddr=ezynq_ddr.EzynqDDR([],permit_undefined_bits, force, warn_notfit) #regs_masked are just []
ddr.parse_parameters(raw_configs)
ddr_type=ddr.get_ddr_type()
#clk=ezynq_clk.EzynqClk(regs_masked,ddr_type,permit_undefined_bits=False,force=False,warn=False)
clk=ezynq_clk.EzynqClk([],ddr_type,permit_undefined_bits,force,warn_notfit) # will it verify memory type is set?
clk.parse_parameters(raw_configs)
clk.calculate_dependent_pars() # will calculate DDR clock, needed for ddr.calculate_dependent_pars()
clk.check_missing_features() #and apply default values
clk.check_ds_compliance()
clk.setup_clocks()
ddr_mhz=clk.get_ddr_mhz()
if MIO_HTML:
f=open(MIO_HTML,'w')
......@@ -302,12 +315,15 @@ mio_regs.output_mio(f,MIO_HTML_MASK)
# setregs_mio(self,current_reg_sets,force=True):
#output_mio(registers,f,mio,MIO_HTML_MASK)
ddr.calculate_dependent_pars()
ddr.calculate_dependent_pars(ddr_mhz)
ddr.pre_validate() # before applying default values (some timings should be undefined, not defaults)
ddr.check_missing_features() #and apply default values
ddr.html_list_features(f) #verify /fix values after defaults are applied
#ddr.ddr_init_memory(current_reg_sets,force=False,warn=False): # will program to sequence 'MAIN'
#clk.calculate_dependent_pars()
clk.html_list_features(f)
reg_sets=[]
reg_sets=mio_regs.setregs_mio(reg_sets,force) # reg Sets include now MIO
num_mio_regs=len(reg_sets)
......
......@@ -109,11 +109,10 @@ CONFIG_EZYNQ_DDR_RAM_HIGHADDR = 0x3FFFFFFF
##### DDR independent ######
CONFIG_EZYNQ_DDR_ENABLE = Y # Enable DDR memory'},
CONFIG_EZYNQ_DDR_TARGET_FREQ_MHZ = 533.3333 # Target DDR clock frequency in MHz (actual frequency will depend on the clock/clock muxes)
#CONFIG_EZYNQ_DDR_FREQ_MHZ = 545.0 # Actual DDR clock frequency in MHz, may be derived form CONFIG_EZYNQ_DDR_TARGET_FREQ_MHZ and clock multiplexer settings. Causes tWR to go higher
#CONFIG_EZYNQ_DDR_FREQ_MHZ = 533.333374 # Actual DDR clock frequency in MHz, may be derived form CONFIG_EZYNQ_DDR_TARGET_FREQ_MHZ and clock multiplexer settings. Causes tWR to go higher
CONFIG_EZYNQ_DDR_FREQ_MHZ = 533.3333 # Actual DDR clock frequency in MHz, may be derived form CONFIG_EZYNQ_DDR_TARGET_FREQ_MHZ and clock multiplexer settings
CONFIG_EZYNQ_DDR_ENABLE = Y # Enable DDR memory'},
# CONFIG_EZYNQ_DDR_FREQ_MHZ = 533.333374 # DDR clock frequency in MHz, this value overwrites the one calculated by the PLL/clock setup
# CONFIG_EZYNQ_DDR_FREQ_MHZ = 533.333333 # DDR clock frequency in MHz, this value overwrites the one calculated by the PLL/clock setup
CONFIG_EZYNQ_DDR_BANK_ADDR_MAP = 10 # DRAM address mapping: number of combined column and row addresses lower than BA0
CONFIG_EZYNQ_DDR_ARB_PAGE_BANK = N # Enable Arbiter prioritization based on page/bank match
CONFIG_EZYNQ_DDR_ECC = Disabled # Enable ECC for the DDR memory
......@@ -143,7 +142,8 @@ CONFIG_EZYNQ_DDR_BIDIR_DRIVE_NEG = 12 # Drive strength negative for drivi
CONFIG_EZYNQ_DDR_BIDIR_DRIVE_POS = 28 # Slew rate positive for driving DDR DQ/DQS signals
###### DDR Datasheet (can be in include file) #######
CONFIG_EZYNQ_DDR_DS_PARTNO = MT41K256M16RE125 # Memory part number (currently not used - derive some parameters later)
CONFIG_EZYNQ_DDR_DS_MEMORY_TYPE = DDR3L # DDR memory type: DDR3 (1.5V), DDR3L (1.35V), DDR2 (1.8V), LPDDR2 (1.2V)
#CONFIG_EZYNQ_DDR_DS_MEMORY_TYPE = DDR3L # DDR memory type: DDR3 (1.5V), DDR3L (1.35V), DDR2 (1.8V), LPDDR2 (1.2V)
CONFIG_EZYNQ_DDR_DS_BANK_ADDR_COUNT = 3 # Number of DDR banks
CONFIG_EZYNQ_DDR_DS_ROW_ADDR_COUNT = 15 # Number of DDR Row Address bits
CONFIG_EZYNQ_DDR_DS_COL_ADDR_COUNT = 10 # Number of DDR Column address bits
......@@ -239,3 +239,68 @@ CONFIG_EZYNQ_DDR_CLOCK_0_PROPOGATION_DELAY = 160
CONFIG_EZYNQ_DDR_CLOCK_1_PROPOGATION_DELAY = 160
CONFIG_EZYNQ_DDR_CLOCK_2_PROPOGATION_DELAY = 160
CONFIG_EZYNQ_DDR_CLOCK_3_PROPOGATION_DELAY = 160
############# Main clock settings #############
CONFIG_EZYNQ_CLK_PS_MHZ = 33.333333 # PS_CLK System clock input frequency (MHz)
CONFIG_EZYNQ_CLK_DDR_MHZ = 533.333333 # DDR clock frequency - DDR_3X (MHz)
CONFIG_EZYNQ_CLK_ARM_MHZ = 640#667 # ARM CPU clock frequency cpu_6x4x (MHz)
CONFIG_EZYNQ_CLK_CPU_MODE = 6_2_1 # CPU clocks set 6:2:1 (6:3:2:1) or 4:2:1 (4:2:2:1)
############# Normally do not need to be modified #############
CONFIG_EZYNQ_CLK_DDR_DCI_MHZ = 10.0 # DDR DCI clock frequency (MHz). Normally 10 Mhz'},
CONFIG_EZYNQ_CLK_DDR2X_MHZ = 355.556 # DDR2X clock frequency (MHz). Does not need to be exactly 2/3 of DDR3X clock'},
CONFIG_EZYNQ_CLK_DDR_DCI_MHZ= 10.0 # DDR DCI clock frequency (MHz). Normally 10Mhz
CONFIG_EZYNQ_CLK_SMC_MHZ = 100.0 # Static memory controller clock frequency (MHz). Normally 100 Mhz
CONFIG_EZYNQ_CLK_QSPI_MHZ = 200.0 # Quad SPI memory controller clock frequency (MHz). Normally 200 Mhz
CONFIG_EZYNQ_CLK_GIGE_MHZ = 125.0 # GigE Ethernet controller reference clock frequency (MHz). Normally 125 Mhz
CONFIG_EZYNQ_CLK_SDIO_MHZ = 100.0 # SDIO controller reference clock frequency (MHz). Normally 100 Mhz
CONFIG_EZYNQ_CLK_UART_MHZ = 25.0 # UART controller reference clock frequency (MHz). Normally 25 Mhz
CONFIG_EZYNQ_CLK_SPI_MHZ = 200.0 # SPI controller reference clock frequency (MHz). Normally 200 Mhz
CONFIG_EZYNQ_CLK_CAN_MHZ = 100.0 # CAN controller reference clock frequency (MHz). Normally 100 Mhz
CONFIG_EZYNQ_CLK_PCAP_MHZ = 200.0 # PCAP clock frequency (MHz). Normally 200 Mhz
CONFIG_EZYNQ_CLK_TRACE_MHZ = 100.0 # Trace Port clock frequency (MHz). Normally 100 Mhz
CONFIG_EZYNQ_CLK_PLL_FCLK_MHZ = 50.0 # PLL DCLK clock frequency (MHz). Normally 50 Mhz
CONFIG_EZYNQ_CLK_ARM_SRC = ARM # ARM CPU clock source (normally ARM PLL)'},
CONFIG_EZYNQ_CLK_DDR_SRC = DDR # DDR (DDR2x, DDR3x) clock source (normally DDR PLL)'},
CONFIG_EZYNQ_CLK_DCI_SRC = DDR # DDR DCI clock source (normally DDR PLL)'},
CONFIG_EZYNQ_CLK_SMC_SRC = IO # Static memory controller clock source (normally IO PLL)'},
CONFIG_EZYNQ_CLK_QSPI_SRC = IO # Quad SPI memory controller clock source (normally IO PLL)'},
CONFIG_EZYNQ_CLK_GIGE_SRC = IO # GigE Ethernet controller clock source (normally IO PLL)'},
CONFIG_EZYNQ_CLK_SDIO_SRC = IO # SDIO controller clock source (normally IO PLL)'},
CONFIG_EZYNQ_CLK_UART_SRC = IO # UART controller clock source (normally IO PLL)'},
CONFIG_EZYNQ_CLK_SPI_SRC = IO # SPI controller clock source (normally IO PLL)'},
CONFIG_EZYNQ_CLK_CAN_SRC = IO # CAN controller clock source (normally IO PLL)'},
CONFIG_EZYNQ_CLK_PCAP_SRC = IO # PCAP controller clock source (normally IO PLL)'},
CONFIG_EZYNQ_CLK_TRACE_SRC = IO # Trace Port clock source (normally IO PLL)'},
CONFIG_EZYNQ_CLK_PLL_FCLK_SRC = IO # PLL FCLK clock source (normally IO PLL)'},
CONFIG_EZYNQ_DDR_DS_MEMORY_TYPE = DDR3 # DDR memory type: DDR3 (1.5V), DDR3L (1.35V), DDR2 (1.8V), LPDDR2 (1.2V)
##### performance data, final values (overwrite calculated) #####
CONFIG_EZYNQ_CLK_SPEED_GRADE = 3 # Device speed grade
#CONFIG_EZYNQ_CLK_PLL_MAX_MHZ = 1800.0 # Maximal PLL clock frequency, MHz. Overwrites default for selected speed grade: (Speed grade -1:1600, -2:1800, -3:2000)'},
#CONFIG_EZYNQ_CLK_PLL_MIN_MHZ = 780.0 # Minimal PLL clock frequency, all speed grades (MHz)'},
#CONFIG_EZYNQ_CLK_ARM621_MAX_MHZ = 733.0 # Maximal ARM clk_6x4x in 621 mode, MHz. Overwrites default for selected speed grade: (Speed grade -1:667, -2:733, -3:1000)'},
#CONFIG_EZYNQ_CLK_ARM421_MAX_MHZ = 600.0 # Maximal ARM clk_6x4x in 421 mode, MHz. Overwrites default for selected speed grade: (Speed grade -1:533, -2:600, -3:710)'},
#CONFIG_EZYNQ_CLK_DDR_3X_MAX_MHZ = 533.0 # Maximal DDR clk_3x clock frequency (MHz). Overwrites DDR-type/speed grade specific'},
#CONFIG_EZYNQ_CLK_DDR_2X_MAX_MHZ = 408.0 # Maximal DDR_2X clock frequency (MHz). Overwrites speed grade specific'},
##### datasheet data for specific speed grades #####
CONFIG_EZYNQ_CLK_DS_PLL_MAX_1_MHZ = 1600.0 # Maximal PLL clock frequency for speed grade 1 (MHz)'},
CONFIG_EZYNQ_CLK_DS_PLL_MAX_2_MHZ = 1800.0 # Maximal PLL clock frequency for speed grade 2 (MHz)'},
CONFIG_EZYNQ_CLK_DS_PLL_MAX_3_MHZ = 2000.0 # Maximal PLL clock frequency for speed grade 3 (MHz)'},
CONFIG_EZYNQ_CLK_DS_ARM621_MAX_1_MHZ = 667.0 # Maximal ARM clk_6x4x in 621 mode for speed grade 1, MHz'},
CONFIG_EZYNQ_CLK_DS_ARM621_MAX_2_MHZ = 733.0 #Maximal ARM clk_6x4x in 621 mode for speed grade 2, MHz'},
CONFIG_EZYNQ_CLK_DS_ARM621_MAX_3_MHZ =1000.0 #Maximal ARM clk_6x4x in 621 mode for speed grade 3, MHz'},
CONFIG_EZYNQ_CLK_DS_ARM421_MAX_1_MHZ = 533.0 # Maximal ARM clk_6x4x in 421 mode for speed grade 1, MHz'},
CONFIG_EZYNQ_CLK_DS_ARM421_MAX_2_MHZ = 600.0 # Maximal ARM clk_6x4x in 421 mode for speed grade 2, MHz'},
CONFIG_EZYNQ_CLK_DS_ARM421_MAX_3_MHZ = 710.0 # Maximal ARM clk_6x4x in 421 mode for speed grade 3, MHz'},
CONFIG_EZYNQ_CLK_DS_DDR3_MAX_1_MBPS = 1066.0 # Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 1'},
CONFIG_EZYNQ_CLK_DS_DDR3_MAX_2_MBPS = 1066.0 # Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 2'},
CONFIG_EZYNQ_CLK_DS_DDR3_MAX_3_MBPS = 1333.0 # Maximal DDR3 performance in Mb/s - twice clock frequency (MHz). Speed grade 3'},
CONFIG_EZYNQ_CLK_DS_DDRX_MAX_X_MBPS = 800.0 # Maximal DDR3L, DDR2, LPDDR2 performance in Mb/s - twice clock frequency (MHz). All speed grades'},
CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_1_MHZ = 355.0 # Maximal DDR_2X clock frequency (MHz) for speed grade 1'},
CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_2_MHZ = 408.0 # Maximal DDR_2X clock frequency (MHz) for speed grade 2'},
CONFIG_EZYNQ_CLK_DS_DDR_2X_MAX_3_MHZ = 444.0 # Maximal DDR_2X clock frequency (MHz) for speed grade 3'},
CONFIG_EZYNQ_CLK_COMPLIANCE_PERCENT = 5.0 # Allow exceeding maximal limits by this margin (percent'},
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment