-
-
Save a3f/085ea5d58e3bf3e5536e441b1a45f0ce to your computer and use it in GitHub Desktop.
EZchip clock driver generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
# StarFive software release has a few thousand lines of macro soup | |
# apparently generated from HDL. This script generates common clk | |
# framework-like-code out of it | |
# Usage: ./scripts/ezchip-clk-parse.pl clkgen_ctrl_macro.h | |
use strict; | |
use warnings; | |
my %clks; | |
while (<>) { | |
if (/^#define\s+clk_(.+)_ctrl_REG_ADDR\s+CLKGEN_BASE_ADDR \+ (.+)$/) { | |
$clks{$1} = { offset => $2 }; | |
$clks{$1}{parents} = {}; | |
$clks{$1}{type} = ''; | |
} | |
if (/^#define\s+_SWITCH_CLOCK_clk_(.+)_SOURCE_(.+)_\s*\{\s*\\/) { | |
$clks{$1}{type} = 'mux'; | |
my $remainder = ''; | |
my $src = $2; | |
while (<>) { | |
$remainder .= $_; | |
s/(\|=.*)\);/$1<<0/; | |
last if /\}/; | |
} | |
if ($remainder =~ | |
/\s*uint32_t\s+_ezchip_macro_read_value_\s*=\s*MA_INW\(clk_(.+)_ctrl_REG_ADDR\);\s*\\ | |
\s*_ezchip_macro_read_value_\s*&=\s*~.+;\s*\\ | |
\s*_ezchip_macro_read_value_\s*\|=\s*\((.+)&(.+)\)<<(.+);\s*\\ | |
\s*MA_OUTW\(clk_(.+)_ctrl_REG_ADDR,_ezchip_macro_read_value_\);\s*\\ | |
\}/s) { | |
my $value = hex($2); | |
$clks{$1}{parents}{$value} = { name => $src, mask => hex($3), shift => $4 }; | |
} else { | |
die "couldn't parse $remainder\n"; | |
} | |
} | |
if (/^#define\s+_ENABLE_CLOCK_clk_(.+)_\s*{\s*\\/) { | |
$clks{$1}{type} .= 'gate'; | |
my $remainder = ''; | |
while (<>) { | |
$remainder .= $_; | |
s/(\|=.*)\);/$1<<0/; | |
last if /\}/; | |
} | |
if ($remainder =~ | |
/\s*uint32_t\s+_ezchip_macro_read_value_\s*=\s*MA_INW\(clk_(.+)_ctrl_REG_ADDR\);\s*\\ | |
\s*_ezchip_macro_read_value_\s*&=\s*~.+;\s*\\ | |
\s*_ezchip_macro_read_value_\s*\|=\s*\((.+)&(.+)\)<<(.+);\s*\\ | |
\s*MA_OUTW\(clk_(.+)_ctrl_REG_ADDR,_ezchip_macro_read_value_\);\s*\\ | |
\}/s) { | |
my $value = hex($2); | |
$clks{$1}{mask} = hex($3); | |
$clks{$1}{shift} = $4; | |
} else { | |
die "couldn't parse $remainder\n"; | |
} | |
} | |
if (/^#define\s+_SET_CLOCK_clk_(.+)_POLARITY_\s*{\s*\\/) { | |
$clks{$1}{type} .= 'inverter'; | |
my $remainder = ''; | |
while (<>) { | |
$remainder .= $_; | |
s/(\|=.*)\);/$1<<0/; | |
last if /\}/; | |
} | |
if ($remainder =~ | |
/\s*uint32_t\s+_ezchip_macro_read_value_\s*=\s*MA_INW\(clk_(.+)_ctrl_REG_ADDR\);\s*\\ | |
\s*_ezchip_macro_read_value_\s*&=\s*~.+;\s*\\ | |
\s*_ezchip_macro_read_value_\s*\|=\s*\((.+)&(.+)\)<<(.+);\s*\\ | |
\s*MA_OUTW\(clk_(.+)_ctrl_REG_ADDR,_ezchip_macro_read_value_\);\s*\\ | |
\}/s) { | |
my $value = hex($2); | |
$clks{$1}{mask} = hex($3); | |
$clks{$1}{shift} = $4; | |
} else { | |
die "couldn't parse $remainder\n"; | |
} | |
} | |
if (/^#define\s+_DIVIDE_CLOCK_clk_(.+)_\s*\(div\)\s*{\s*\\/) { | |
$clks{$1}{type} .= 'divider'; | |
my $remainder = ''; | |
while (<>) { | |
s/(\|=.*)\);/$1\)<<0;/; | |
$remainder .= $_; | |
last if /\}/; | |
} | |
if ($remainder =~ | |
/\s*uint32_t\s+_ezchip_macro_read_value_\s*=\s*MA_INW\(clk_(.+)_ctrl_REG_ADDR\);\s*\\ | |
\s*_ezchip_macro_read_value_\s*&=\s*~.+;\s*\\ | |
\s*_ezchip_macro_read_value_\s*\|=\s*\((.+)&(.+)\)<<(.+);\s*\\ | |
\s*MA_OUTW\(clk_(.+)_ctrl_REG_ADDR,_ezchip_macro_read_value_\);\s*\\ | |
\}/s) { | |
$clks{$1}{mask} = hex($3); | |
$clks{$1}{shift} = $4; | |
} else { | |
die "couldn't parse $remainder\n"; | |
} | |
} | |
} | |
my @sorted_clk_names = sort { hex $clks{$a}{offset} <=> hex $clks{$b}{offset} } keys %clks; | |
my $i = 0; | |
for my $name (@sorted_clk_names) { | |
printf "#define EZCHIP_CLK_%s\t\t%u\n", uc($name), ++$i | |
} | |
print "\n\n\n"; | |
for my $name (@sorted_clk_names) { | |
my $clk = $clks{$name}; | |
my $max = 1; | |
my $last = 0; | |
my $parents = ''; | |
my %shifts; | |
for my $parent (values(%{$clk->{parents}})) { | |
$max = $parent->{mask} > $max ? $parent->{mask} + 1 : $max; | |
$shifts{$parent->{shift}} = 1; | |
} | |
my $shifts = keys(%shifts); | |
next if $shifts == 0; | |
print "static const char \*${name}_sels\[$max\] = {\n"; | |
die "// Invalid #shifts = $shifts ^" if $shifts != 1; | |
$clk->{shift} = @{[keys(%shifts)]}[0]; | |
$clk->{mask} = $max; | |
for (my $i = 0; $i < $max; $i++) { | |
my $parent = %{$clk->{parents}}{$i}; | |
print "\t[$i] = "; | |
if (not defined $parent) { | |
print "\"dummy\",\n"; | |
} else { | |
printf "\"%s\",\n", $parent->{name}; | |
} | |
} | |
print "}\n\n"; | |
} | |
print "\n\n\n"; | |
sub log2 { log(shift) / log(2) } | |
for my $name (@sorted_clk_names) { | |
my $clk = $clks{$name}; | |
my $offset = $clk->{offset}; | |
my $shift = $clk->{shift} // 0; | |
my $width = defined $clk->{mask} ? log2($clk->{mask} + 1) : 'UNKNOWN'; | |
my $parent = ""; | |
my $type = $clk->{type} // 'FIXME'; | |
my @extra; | |
$type =~ s/gatedivider/gated_divider/; | |
my $idx = "EZCHIP_CLK_" . uc($name); | |
print "\tclks[EZCHIP_CLK_" . uc($name). qq{]\t\t= ezchip_clk_$type("$name",\t\t"$parent",\t\tbase + $offset, $shift, $width}; | |
if ($clk->{type} eq 'mux') { | |
print ", ${name}_sels, ARRAY_SIZE(${name}_sels));"; | |
} else { | |
} | |
print qq{);\n}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment