embeddedsw/XilinxProcessorIPLib/drivers/scugic/data/scugic.tcl
Kinjal Pravinbhai Patel ee6224443b drivers: scugic: tcl has been modified for proper error message
This patch modifies driver tcl to show proper error message when
unsupported combination of IP and processor instance tries to
generate BSP e.g. if psu_rcpu_gic is not supported with cortex a53
and psu_acpu_gic is not supported with cortex r5

Signed-off-by: Kinjal Pravinbhai Patel <patelki@xilinx.com>
Acked-by: Anirudha Sarangi <anirudh@xilinx.com>
2015-09-04 22:00:09 +05:30

583 lines
23 KiB
Tcl
Executable file

###############################################################################
#
# Copyright (C) 2011 - 2015 Xilinx, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# Use of the Software is limited solely to applications:
# (a) running on a Xilinx device, or
# (b) that interact with a Xilinx device through a bus or interconnect.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Except as contained in this notice, the name of the Xilinx shall not be used
# in advertising or otherwise to promote the sale, use or other dealings in
# this Software without prior written authorization from Xilinx.
#
###############################################################################
##############################################################################
#
# Modification History
#
# Ver Who Date Changes
# ----- ---- -------- -----------------------------------------------
# 1.00a sdm 04/18/11 Created
# 1.05a hk 06/26/13 Modified to export external interrupts correctly
# to xparameters.h. Fix for CR's 690505, 708928 & 719359
# 2.0 adk 12/10/13 Updated as per the New Tcl API's
# 2.1 adk 25/04/14 Added support for corenIRQ/FIQ interrupts.Fix for the
# CR#789373
# 3.0 pkp 12/09/14 Added support for Zynq Ultrascale Mp
##############################################################################
#uses "xillib.tcl"
############################################################
# "generate" procedure
############################################################
proc generate {drv_handle} {
xdefine_gic_params $drv_handle
xdefine_zynq_include_file $drv_handle "xparameters.h" "XScuGic" "NUM_INSTANCES" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_DIST_BASEADDR"
xdefine_zynq_config_file $drv_handle "xscugic_g.c" "XScuGic" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_DIST_BASEADDR"
xdefine_zynq_canonical_xpars $drv_handle "xparameters.h" "ScuGic" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_DIST_BASEADDR"
}
#
# Given a list of arguments, define them all in an include file.
# Similar to proc xdefine_include_file, except that uses regsub
# to replace "S_AXI_" with "".
#
proc xdefine_zynq_include_file {drv_handle file_name drv_string args} {
# Open include file
set file_handle [::hsi::utils::open_include_file $file_name]
# Get all peripherals connected to this driver
set periphs [::hsi::utils::get_common_driver_ips $drv_handle]
#Get the processor instance name
set sw_proc_handle [hsi::get_sw_processor]
set hw_proc_handle [hsi::get_cells -hier [common::get_property HW_INSTANCE $sw_proc_handle] ]
set proctype [common::get_property IP_NAME $hw_proc_handle]
set valid_periph 0
#Get proper gic instance for periphs in case of zynqmp
foreach periph $periphs {
if {([string compare -nocase $proctype "ps7_cortexa9"] == 0)||
(([string compare -nocase $proctype "psu_cortexa53"] == 0)&&([string compare -nocase $periph "psu_acpu_gic"] == 0))||
(([string compare -nocase $proctype "psu_cortexr5"] == 0)&&([string compare -nocase $periph "psu_rcpu_gic"] == 0))} {
lappend newperiphs $periph
set valid_periph 1
}
}
if {!$valid_periph } {
error "The scugic driver is not supported for the combination of selected IP and processor";
return;
}
set periphs $newperiphs
# Handle special cases
set arg "NUM_INSTANCES"
set posn [lsearch -exact $args $arg]
if {$posn > -1} {
puts $file_handle "/* Definitions for driver [string toupper [common::get_property NAME $drv_handle]] */"
# Define NUM_INSTANCES
puts $file_handle "#define [::hsi::utils::get_driver_param_name $drv_string $arg] [llength $periphs]"
set args [lreplace $args $posn $posn]
}
# Check if it is a driver parameter
lappend newargs
foreach arg $args {
set value [common::get_property CONFIG.$arg $drv_handle]
if {[llength $value] == 0} {
lappend newargs $arg
} else {
puts $file_handle "#define [::hsi::utils::get_driver_param_name $drv_string $arg] [common::get_property CONFIG.$arg $drv_handle]"
}
}
set args $newargs
# Print all parameters for all peripherals
set device_id 0
foreach periph $periphs {
puts $file_handle ""
puts $file_handle "/* Definitions for peripheral [string toupper [common::get_property NAME $periph]] */"
foreach arg $args {
if {[string compare -nocase "DEVICE_ID" $arg] == 0} {
set value $device_id
incr device_id
} elseif {[string compare -nocase "C_S_AXI_BASEADDR" $arg] == 0} {
if {[string compare -nocase $proctype "psu_cortexr5"] == 0} {
set value 0xF9001000
} elseif {[string compare -nocase $proctype "ps7_cortexa9"] == 0} {
set value [common::get_property CONFIG.$arg $periph]
} else {
set value 0xF9020000
}
} elseif {[string compare -nocase "C_S_AXI_HIGHADDR" $arg] == 0} {
if {[string compare -nocase $proctype "psu_cortexr5"] == 0} {
set value 0xF9001FFF
} elseif {[string compare -nocase $proctype "ps7_cortexa9"] == 0} {
set value [common::get_property CONFIG.$arg $periph]
} else {
set value 0xF9020FFF
}
} elseif {[string compare -nocase "C_DIST_BASEADDR" $arg] == 0} {
if {[string compare -nocase $proctype "psu_cortexr5"] == 0} {
set value 0xF9000000
} elseif {[string compare -nocase $proctype "ps7_cortexa9"] == 0} {
set value 0xf8f01000
} else {
set value 0xF9010000
}
} else {
set value [common::get_property CONFIG.$arg $periph]
}
if {[llength $value] == 0} {
set value 0
}
set value [::hsi::utils::format_addr_string $value $arg]
set arg_name [::hsi::utils::get_ip_param_name $periph $arg]
regsub "S_AXI_" $arg_name "" arg_name
if {[string compare -nocase "HW_VER" $arg] == 0} {
puts $file_handle "#define $arg_name \"$value\""
} else {
puts $file_handle "#define $arg_name $value"
}
}
puts $file_handle ""
}
puts $file_handle "\n/******************************************************************/\n"
close $file_handle
}
#-----------------------------------------------------------------------------
# xdefine_zynq_canonical_xpars - Used to print out canonical defines for a driver.
# Similar to proc xdefine_config_file, except that uses regsub to replace "S_AXI_"
# with "".
#-----------------------------------------------------------------------------
proc xdefine_zynq_canonical_xpars {drv_handle file_name drv_string args} {
# Open include file
set file_handle [::hsi::utils::open_include_file $file_name]
# Get all the peripherals connected to this driver
set periphs [::hsi::utils::get_common_driver_ips $drv_handle]
#Get the processor instance name
set sw_proc_handle [hsi::get_sw_processor]
set hw_proc_handle [hsi::get_cells -hier [common::get_property HW_INSTANCE $sw_proc_handle] ]
set proctype [common::get_property IP_NAME $hw_proc_handle]
set valid_periph 0
#Get proper gic instance for periphs in case of zynqmp
foreach periph $periphs {
if {([string compare -nocase $proctype "ps7_cortexa9"] == 0)||
(([string compare -nocase $proctype "psu_cortexa53"] == 0)&&([string compare -nocase $periph "psu_acpu_gic"] == 0))||
(([string compare -nocase $proctype "psu_cortexr5"] == 0)&&([string compare -nocase $periph "psu_rcpu_gic"] == 0))} {
lappend newperiphs $periph
set valid_periph 1
}
}
if {!$valid_periph } {
error "The scugic driver is not supported for the combination of selected IP and processor";
return;
}
set periphs $newperiphs
# Get the names of all the peripherals connected to this driver
foreach periph $periphs {
set peripheral_name [string toupper [common::get_property NAME $periph]]
lappend peripherals $peripheral_name
}
# Get possible canonical names for all the peripherals connected to this
# driver
set device_id 0
foreach periph $periphs {
set canonical_name [string toupper [format "%s_%s" $drv_string $device_id]]
lappend canonicals $canonical_name
# Create a list of IDs of the peripherals whose hardware instance name
# doesn't match the canonical name. These IDs can be used later to
# generate canonical definitions
if { [lsearch $peripherals $canonical_name] < 0 } {
lappend indices $device_id
}
incr device_id
}
set i 0
foreach periph $periphs {
set periph_name [string toupper [common::get_property NAME $periph]]
# Generate canonical definitions only for the peripherals whose
# canonical name is not the same as hardware instance name
if { [lsearch $canonicals $periph_name] < 0 } {
puts $file_handle "/* Canonical definitions for peripheral $periph_name */"
set canonical_name [format "%s_%s" $drv_string [lindex $indices $i]]
foreach arg $args {
set lvalue [::hsi::utils::get_driver_param_name $canonical_name $arg]
# replace S_SXI_ with CPU_. This is a temporary fix. Revist when the
# S_AXI_DIST_BASEADDR is generated by the tools
regsub "S_AXI_" $lvalue "CPU_" lvalue
# The commented out rvalue is the name of the instance-specific constant
# set rvalue [::hsi::utils::get_ip_param_name $periph $arg]
# The rvalue set below is the actual value of the parameter
if {[string compare -nocase "C_S_AXI_BASEADDR" $arg] == 0} {
if {[string compare -nocase $proctype "psu_cortexr5"] == 0} {
set rvalue 0xF9001000
} elseif {[string compare -nocase $proctype "ps7_cortexa9"] == 0} {
set rvalue [common::get_property CONFIG.$arg $periph]
} else {
set rvalue 0xF9020000
}
} elseif {[string compare -nocase "C_S_AXI_HIGHADDR" $arg] == 0} {
if {[string compare -nocase $proctype "psu_cortexr5"] == 0} {
set rvalue 0xF9001FFF
} elseif {[string compare -nocase $proctype "ps7_cortexa9"] == 0} {
set rvalue [common::get_property CONFIG.$arg $periph]
} else {
set rvalue 0xF9020FFF
}
} elseif {[string compare -nocase "C_DIST_BASEADDR" $arg] == 0} {
if {[string compare -nocase $proctype "psu_cortexr5"] == 0} {
set rvalue 0xF9000000
} elseif {[string compare -nocase $proctype "ps7_cortexa9"] == 0} {
set rvalue 0xf8f01000
} else {
set rvalue 0xF9010000
}
} else {
set rvalue [common::get_property CONFIG.$arg $periph]
}
if {[llength $rvalue] == 0} {
set rvalue 0
}
set rvalue [::hsi::utils::format_addr_string $rvalue $arg]
puts $file_handle "#define $lvalue $rvalue"
}
puts $file_handle ""
incr i
}
}
puts $file_handle "\n/******************************************************************/\n"
close $file_handle
}
#
# Create configuration C file as required by Xilinx Zynq drivers
# Similar to proc define_config_file, except that uses regsub
# to replace "S_AXI_" with ""
#
proc xdefine_zynq_config_file {drv_handle file_name drv_string args} {
set args [::hsi::utils::get_exact_arg_list $args]
set filename [file join "src" $file_name]
#file delete $filename
set config_file [open $filename w]
::hsi::utils::write_c_header $config_file "Driver configuration"
puts $config_file "#include \"xparameters.h\""
puts $config_file "#include \"[string tolower $drv_string].h\""
puts $config_file "\n/*"
puts $config_file "* The configuration table for devices"
puts $config_file "*/\n"
puts $config_file [format "%s_Config %s_ConfigTable\[\] =" $drv_string $drv_string]
puts $config_file "\{"
set periphs [::hsi::utils::get_common_driver_ips $drv_handle]
#Get the processor instance name
set sw_proc_handle [hsi::get_sw_processor]
set hw_proc_handle [hsi::get_cells -hier [common::get_property HW_INSTANCE $sw_proc_handle] ]
set proctype [common::get_property IP_NAME $hw_proc_handle]
set valid_periph 0
#Get proper gic instance for periphs in case of zynqmp
foreach periph $periphs {
if {([string compare -nocase $proctype "ps7_cortexa9"] == 0)||
(([string compare -nocase $proctype "psu_cortexa53"] == 0)&&([string compare -nocase $periph "psu_acpu_gic"] == 0))||
(([string compare -nocase $proctype "psu_cortexr5"] == 0)&&([string compare -nocase $periph "psu_rcpu_gic"] == 0))} {
lappend newperiphs $periph
set valid_periph 1
}
}
if {!$valid_periph } {
error "The scugic driver is not supported for the combination of selected IP and processor";
return;
}
set periphs $newperiphs
set start_comma ""
foreach periph $periphs {
puts $config_file [format "%s\t\{" $start_comma]
set comma ""
foreach arg $args {
# Check if this is a driver parameter or a peripheral parameter
set value [common::get_property CONFIG.$arg $drv_handle]
if {[llength $value] == 0} {
set local_value [common::get_property CONFIG.$arg $periph ]
# If a parameter isn't found locally (in the current
# peripheral), we will (for some obscure and ancient reason)
# look in peripherals connected via point to point links
if { [string compare -nocase $local_value ""] == 0} {
set p2p_name [::hsi::utils::get_p2p_name $periph $arg]
if { [string compare -nocase $p2p_name ""] == 0} {
set arg_name [::hsi::utils::get_ip_param_name $periph $arg]
regsub "S_AXI_" $arg_name "" arg_name
puts -nonewline $config_file [format "%s\t\t%s" $comma $arg_name]
} else {
regsub "S_AXI_" $p2p_name "" p2p_name
puts -nonewline $config_file [format "%s\t\t%s" $comma $p2p_name]
}
} else {
set arg_name [::hsi::utils::get_ip_param_name $periph $arg]
regsub "S_AXI_" $arg_name "" arg_name
puts -nonewline $config_file [format "%s\t\t%s" $comma $arg_name]
}
} else {
set arg_name [::hsi::utils::get_driver_param_name $drv_string $arg]
regsub "S_AXI_" $arg_name "" arg_name
puts -nonewline $config_file [format "%s\t\t%s" $comma $arg_name]
}
set comma ",\n"
}
puts -nonewline $config_file "\n\t\}"
set start_comma ",\n"
}
puts $config_file "\n\};"
puts $config_file "\n";
close $config_file
}
proc xdefine_gic_params {drvhandle} {
#Get the processor instance name
set sw_proc_handle [hsi::get_sw_processor]
set hw_proc_handle [hsi::get_cells -hier [common::get_property HW_INSTANCE $sw_proc_handle] ]
set proctype [common::get_property IP_NAME $hw_proc_handle]
# Fix me
# Avoid generating fabric interrupts for zynqmp till the issue is fixed
if {([string compare -nocase $proctype "psu_cortexa53"] == 0) || ([string compare -nocase $proctype "psu_cortexr5"] == 0)} {
} else {
set config_inc [::hsi::utils::open_include_file "xparameters.h"]
# Next define interrupt IDs for each connected peripheral
set periphs [::hsi::utils::get_common_driver_ips $drvhandle]
set device_id 0
foreach periph $periphs {
# get the gic mode information
set scugic_mode [common::get_property CONFIG.C_IRQ_F2P_MODE $periph]
# Get the edk based name of peripheral for printing redefines
set edk_periph_name [common::get_property NAME $periph]
# Get ports that are driving the interrupt
set source_ports [::hsi::utils::get_interrupt_sources $periph]
set i 0
lappend source_list
foreach source_port $source_ports {
if {[llength $source_port] ==0 } {
continue
}
set portType [common::get_property TYPE $source_port]
if { [string compare -nocase $portType "INTERRUPT"] } {
continue
}
set external_pin [::hsi::utils::is_external_pin $source_port]
if {$external_pin} {
set source_port_name($i) [common::get_property NAME $source_port]
set source_periph($i) ""
set source_name($i) "system"
} else {
set source_port_name($i) [common::get_property NAME $source_port]
set source_ip [hsi::get_cells -of_objects $source_port]
if { [common::get_property IS_PL $source_ip] == 0 } {
#add only PL IP. Return all PS IPs
continue
}
set source_periph($i) $source_ip
set source_name($i) [common::get_property NAME $source_periph($i)]
}
lappend source_list $source_name($i)
incr i
}
set num_intr_inputs $i
if {$num_intr_inputs == 0} {
close $config_inc
return
}
puts $config_inc "/* Definitions for Fabric interrupts connected to $edk_periph_name */"
for {set i 0} {$i < $num_intr_inputs} {incr i} {
set ip_name $source_name($i)
set port_name $source_port_name($i)
set port_obj [::hsi::get_ports $port_name]
set port_intr_id [::hsi::utils::get_interrupt_id $ip_name $port_name]
if { [string compare -nocase $ip_name "system"] } {
set ip_obj [::hsi::get_cells -hier $ip_name]
if {[llength $ip_obj]} {
set port_obj [::hsi::get_pins -of_objects $ip_obj $port_name]
}
} else {
set port_intr_id [::hsi::utils::get_interrupt_id "" $port_name]
}
if { [llength $port_intr_id] > 1 } {
set j 0
foreach intr_id $port_intr_id {
puts $config_inc [format "#define XPAR_FABRIC_%s_%s_INTR %d" \
[string toupper $ip_name] [string toupper "${port_name}$j"] $intr_id ]
incr j
}
} else {
puts $config_inc [format "#define XPAR_FABRIC_%s_%s_INTR %d" \
[string toupper $ip_name] [string toupper $port_name] $port_intr_id]
}
}
puts $config_inc "\n/******************************************************************/\n"
puts $config_inc "/* Canonical definitions for Fabric interrupts connected to $edk_periph_name */"
for {set i 0} {$i < $num_intr_inputs} {incr i} {
# Skip global (external) ports
if {[string compare -nocase $source_periph($i) ""] != 0} {
set drv [::hsi::get_drivers -filter "HW_INSTANCE==$$source_name($i)"]
if {[llength $source_name($i)] != 0 && [llength $drv] != 0} {
set instance [xfind_instance $drv $source_name($i)]
set drvname [common::get_property NAME $drv]
set drvname [string toupper $drvname]
#
# Treat sources with multiple interrupt ports slightly different
# by including the interrupt port name in the canonical constant
# name
#
if { [lcount $source_list $source_name($i)] > 1} {
set port_name [string toupper $source_port_name($i)]
#
# If there are multiple interrupt ports for axi_ethernet, do not include
# the port name in the canonical name, for the port "INTERRUPT". Other ports
# will have the port name in the canonical name. This is to make sure that
# the canonical name for the port INTERRUPT will remain same irrespective of
# whether the design has a single interrupt port or multiple interrupt ports
#
if {[string compare -nocase $drvname "axiethernet"] == 0} {
if {[string compare -nocase $port_name "INTERRUPT"] == 0} {
set first_part [format "#define XPAR_%s_%s_%s_VEC_ID" "FABRIC" $drvname $instance]
} else {
set first_part [format "#define XPAR_%s_%s_%s_%s_VEC_ID" "FABRIC" $drvname $instance $port_name]
}
} else {
set first_part [format "#define XPAR_%s_%s_%s_%s_VEC_ID" "FABRIC" $drvname $instance $port_name]
}
} else {
set first_part [format "#define XPAR_%s_%s_%s_VEC_ID" "FABRIC" $drvname $instance]
}
set second_part [format "XPAR_%s_%s_%s_INTR" "FABRIC" [string toupper $source_name($i)] [string toupper $source_port_name($i)] ]
if {[string compare -nocase $drvname "generic"] != 0} {
puts $config_inc "$first_part $second_part"
}
}
}
}
incr device_id
}
puts $config_inc "\n/******************************************************************/\n"
close $config_inc
}
}
###################################################################
#
# Get the number of elements in the given list that match the
# given entry. Assume elements are strings.
#
###################################################################
proc lcount {list match_entry} {
set len [llength $list]
set count 0
for {set i 0} {$i < $len} {incr i} {
set entry [lindex $list $i]
if { [string compare -nocase $entry $match_entry] == 0} {
incr count
}
}
return $count
}
###################################################################
#
# Get the HW instance number for a particular device. This will be used to enumerate
# the vector ID defines if more than one interrupt from the core is connected to the
# interrupt controller.
#
###################################################################
proc xfind_instance {drvhandle instname} {
set instlist [::hsi::utils::get_common_driver_ips $drvhandle]
set i 0
foreach inst $instlist {
set name [common::get_property NAME $inst]
if {[string compare -nocase $instname $name] == 0} {
return $i
}
incr i
}
set i 0
return $i
}
###################################################################
#
# Get the type of port, whether it is "local" (from an IP), or
# "global" (from external source).
#
###################################################################
proc xget_port_type {port} {
set periph [hsi::get_cells -of_objects $port]
if {[llength $periph] == 0} {
return "global"
} else {
return "local"
}
}