media: ccs: Add the generator for CCS register definitions and limits
Add register definitions of the MIPI CCS 1.1 standard. The CCS driver makes extended use of device's capability registers that are dependent on CCS version. This involves having an in-memory data structure for limit and capability information, creating that data structure and accessing it. The register definitions as well as the definitions of this data structure are generated from a text file using a Perl script. Add the generator script to make it easy to update the generated files. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
parent
67e061f044
commit
1ec0b899c2
1041
Documentation/driver-api/media/drivers/ccs/ccs-regs.txt
Normal file
1041
Documentation/driver-api/media/drivers/ccs/ccs-regs.txt
Normal file
File diff suppressed because it is too large
Load Diff
433
Documentation/driver-api/media/drivers/ccs/mk-ccs-regs
Executable file
433
Documentation/driver-api/media/drivers/ccs/mk-ccs-regs
Executable file
@ -0,0 +1,433 @@
|
||||
#!/usr/bin/perl -w
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
|
||||
# Copyright (C) 2019--2020 Intel Corporation
|
||||
|
||||
use Getopt::Long qw(:config no_ignore_case);
|
||||
use File::Basename;
|
||||
|
||||
my $ccsregs = "ccs-regs.txt";
|
||||
my $header;
|
||||
my $regarray;
|
||||
my $limitc;
|
||||
my $limith;
|
||||
my $kernel;
|
||||
my $help;
|
||||
|
||||
GetOptions("ccsregs|c=s" => \$ccsregs,
|
||||
"header|e=s" => \$header,
|
||||
"regarray|r=s" => \$regarray,
|
||||
"limitc|l=s" => \$limitc,
|
||||
"limith|L=s" => \$limith,
|
||||
"kernel|k" => \$kernel,
|
||||
"help|h" => \$help) or die "can't parse options";
|
||||
|
||||
$help = 1 if ! defined $header || ! defined $limitc || ! defined $limith;
|
||||
|
||||
if (defined $help) {
|
||||
print <<EOH
|
||||
$0 - Create CCS register definitions for C
|
||||
|
||||
usage: $0 -c ccs-regs.txt -e header -r regarray -l limit-c -L limit-header [-k]
|
||||
|
||||
-c ccs register file
|
||||
-e header file name
|
||||
-r register description array file name
|
||||
-l limit and capability array file name
|
||||
-L limit and capability header file name
|
||||
-k generate files for kernel space consumption
|
||||
EOH
|
||||
;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $lh_hdr = ! defined $kernel
|
||||
? '#include "ccs-os.h"' . "\n"
|
||||
: "#include <linux/bits.h>\n#include <linux/types.h>\n";
|
||||
my $uint32_t = ! defined $kernel ? 'uint32_t' : 'u32';
|
||||
my $uint16_t = ! defined $kernel ? 'uint16_t' : 'u16';
|
||||
|
||||
open(my $R, "< $ccsregs") or die "can't open $ccsregs";
|
||||
|
||||
open(my $H, "> $header") or die "can't open $header";
|
||||
my $A;
|
||||
if (defined $regarray) {
|
||||
open($A, "> $regarray") or die "can't open $regarray";
|
||||
}
|
||||
open(my $LC, "> $limitc") or die "can't open $limitc";
|
||||
open(my $LH, "> $limith") or die "can't open $limith";
|
||||
|
||||
my %this;
|
||||
|
||||
sub is_limit_reg($) {
|
||||
my $addr = hex $_[0];
|
||||
|
||||
return 0 if $addr < 0x40; # weed out status registers
|
||||
return 0 if $addr >= 0x100 && $addr < 0xfff; # weed out configuration registers
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
my $uc_header = basename uc $header;
|
||||
$uc_header =~ s/[^A-Z0-9]/_/g;
|
||||
|
||||
my $copyright = "/* Copyright (C) 2019--2020 Intel Corporation */\n";
|
||||
my $license = "SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause";
|
||||
|
||||
for my $fh ($A, $LC) {
|
||||
print $fh "// $license\n$copyright\n" if defined $fh;
|
||||
}
|
||||
|
||||
for my $fh ($H, $LH) {
|
||||
print $fh "/* $license */\n$copyright\n";
|
||||
}
|
||||
|
||||
sub bit_def($) {
|
||||
my $bit = shift @_;
|
||||
|
||||
return "BIT($bit)" if defined $kernel;
|
||||
return "(1U << $bit)" if $bit =~ /^[a-zA-Z0-9_]+$/;
|
||||
return "(1U << ($bit))";
|
||||
}
|
||||
|
||||
print $H <<EOF
|
||||
#ifndef __${uc_header}__
|
||||
#define __${uc_header}__
|
||||
|
||||
EOF
|
||||
;
|
||||
|
||||
print $H "#include <linux/bits.h>\n\n" if defined $kernel;
|
||||
|
||||
print $H <<EOF
|
||||
#define CCS_FL_BASE 16
|
||||
EOF
|
||||
;
|
||||
|
||||
print $H "#define CCS_FL_16BIT " . bit_def("CCS_FL_BASE") . "\n";
|
||||
print $H "#define CCS_FL_32BIT " . bit_def("CCS_FL_BASE + 1") . "\n";
|
||||
print $H "#define CCS_FL_FLOAT_IREAL " . bit_def("CCS_FL_BASE + 2") . "\n";
|
||||
print $H "#define CCS_FL_IREAL " . bit_def("CCS_FL_BASE + 3") . "\n";
|
||||
|
||||
print $H <<EOF
|
||||
#define CCS_R_ADDR(r) ((r) & 0xffff)
|
||||
|
||||
EOF
|
||||
;
|
||||
|
||||
print $A <<EOF
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "ccs-extra.h"
|
||||
#include "ccs-regs.h"
|
||||
|
||||
EOF
|
||||
if defined $A;
|
||||
|
||||
my $uc_limith = basename uc $limith;
|
||||
$uc_limith =~ s/[^A-Z0-9]/_/g;
|
||||
|
||||
print $LH <<EOF
|
||||
#ifndef __${uc_limith}__
|
||||
#define __${uc_limith}__
|
||||
|
||||
$lh_hdr
|
||||
struct ccs_limit {
|
||||
$uint32_t reg;
|
||||
$uint16_t size;
|
||||
$uint16_t flags;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
EOF
|
||||
;
|
||||
print $LH "#define CCS_L_FL_SAME_REG " . bit_def(0) . "\n\n";
|
||||
|
||||
print $LH <<EOF
|
||||
extern const struct ccs_limit ccs_limits[];
|
||||
|
||||
EOF
|
||||
;
|
||||
|
||||
print $LC <<EOF
|
||||
#include "ccs-limits.h"
|
||||
#include "ccs-regs.h"
|
||||
|
||||
const struct ccs_limit ccs_limits[] = {
|
||||
EOF
|
||||
;
|
||||
|
||||
my $limitcount = 0;
|
||||
my $argdescs;
|
||||
my $reglist = "const struct ccs_reg_desc ccs_reg_desc[] = {\n";
|
||||
|
||||
sub name_split($$) {
|
||||
my ($name, $addr) = @_;
|
||||
my $args;
|
||||
|
||||
$name =~ /([^\(]+?)(\(.*)/;
|
||||
($name, $args) = ($1, $2);
|
||||
$args = [split /,\s*/, $args];
|
||||
foreach my $t (@$args) {
|
||||
$t =~ s/[\(\)]//g;
|
||||
$t =~ s/\//\\\//g;
|
||||
}
|
||||
|
||||
return ($name, $addr, $args);
|
||||
}
|
||||
|
||||
sub tabconv($) {
|
||||
$_ = shift;
|
||||
|
||||
my @l = split "\n", $_;
|
||||
|
||||
map {
|
||||
s/ {8,8}/\t/g;
|
||||
s/\t\K +//;
|
||||
} @l;
|
||||
|
||||
return (join "\n", @l) . "\n";
|
||||
}
|
||||
|
||||
sub elem_size(@) {
|
||||
my @flags = @_;
|
||||
|
||||
return 2 if grep /^16$/, @flags;
|
||||
return 4 if grep /^32$/, @flags;
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub arr_size($) {
|
||||
my $this = $_[0];
|
||||
my $size = $this->{elsize};
|
||||
my $h = $this->{argparams};
|
||||
|
||||
foreach my $arg (@{$this->{args}}) {
|
||||
my $apref = $h->{$arg};
|
||||
|
||||
$size *= $apref->{max} - $apref->{min} + 1;
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
sub print_args($$$) {
|
||||
my ($this, $postfix, $is_same_reg) = @_;
|
||||
my ($args, $argparams, $name) =
|
||||
($this->{args}, $this->{argparams}, $this->{name});
|
||||
my $varname = "ccs_reg_arg_" . (lc $name) . $postfix;
|
||||
my @mins;
|
||||
my @sorted_args = @{$this->{sorted_args}};
|
||||
my $lim_arg;
|
||||
my $size = arr_size($this);
|
||||
|
||||
$argdescs .= "static const struct ccs_reg_arg " . $varname . "[] = {\n";
|
||||
|
||||
foreach my $sorted_arg (@sorted_args) {
|
||||
push @mins, $argparams->{$sorted_arg}->{min};
|
||||
}
|
||||
|
||||
foreach my $sorted_arg (@sorted_args) {
|
||||
my $h = $argparams->{$sorted_arg};
|
||||
|
||||
$argdescs .= "\t{ \"$sorted_arg\", $h->{min}, $h->{max}, $h->{elsize} },\n";
|
||||
|
||||
$lim_arg .= defined $lim_arg ? ", $h->{min}" : "$h->{min}";
|
||||
}
|
||||
|
||||
$argdescs .= "};\n\n";
|
||||
|
||||
$reglist .= "\t{ CCS_R_" . (uc $name) . "(" . (join ",", (@mins)) .
|
||||
"), $size, sizeof($varname) / sizeof(*$varname)," .
|
||||
" \"" . (lc $name) . "\", $varname },\n";
|
||||
|
||||
print $LC tabconv sprintf "\t{ CCS_R_" . (uc $name) . "($lim_arg), " .
|
||||
$size . ", " . ($is_same_reg ? "CCS_L_FL_SAME_REG" : "0") .
|
||||
", \"$name" . (defined $this->{discontig} ? " $lim_arg" : "") . "\" },\n"
|
||||
if is_limit_reg $this->{base_addr};
|
||||
}
|
||||
|
||||
my $hdr_data;
|
||||
|
||||
while (<$R>) {
|
||||
chop;
|
||||
s/^\s*//;
|
||||
next if /^[#;]/ || /^$/;
|
||||
if (s/^-\s*//) {
|
||||
if (s/^b\s*//) {
|
||||
my ($bit, $addr) = split /\t+/;
|
||||
$bit = uc $bit;
|
||||
$hdr_data .= sprintf "#define %-62s %s", "CCS_" . (uc ${this{name}}) ."_$bit", bit_def($addr) . "\n";
|
||||
} elsif (s/^f\s*//) {
|
||||
s/[,\.-]/_/g;
|
||||
my @a = split /\s+/;
|
||||
my ($msb, $lsb, $this_field) = reverse @a;
|
||||
@a = ( { "name" => "SHIFT", "addr" => $lsb, "fmt" => "%uU", },
|
||||
{ "name" => "MASK", "addr" => (1 << ($msb + 1)) - 1 - ((1 << $lsb) - 1), "fmt" => "0x%" . join(".", ($this{"elsize"} >> 2) x 2) . "x" } );
|
||||
$this{"field"} = $this_field;
|
||||
foreach my $ar (@a) {
|
||||
#print $ar->{fmt}."\n";
|
||||
$hdr_data .= sprintf "#define %-62s " . $ar->{"fmt"} . "\n", "CCS_" . (uc $this{"name"}) . (defined $this_field ? "_" . uc $this_field : "") . "_" . $ar->{"name"}, $ar->{"addr"} . "\n";
|
||||
}
|
||||
} elsif (s/^e\s*//) {
|
||||
s/[,\.-]/_/g;
|
||||
my ($enum, $addr) = split /\s+/;
|
||||
$enum = uc $enum;
|
||||
$hdr_data .= sprintf "#define %-62s %s", "CCS_" . (uc ${this{name}}) . (defined $this{"field"} ? "_" . uc $this{"field"} : "") ."_$enum", $addr . ($addr =~ /0x/i ? "" : "U") . "\n";
|
||||
} elsif (s/^l\s*//) {
|
||||
my ($arg, $min, $max, $elsize, @discontig) = split /\s+/;
|
||||
my $size;
|
||||
|
||||
foreach my $num ($min, $max) {
|
||||
$num = hex $num if $num =~ /0x/i;
|
||||
}
|
||||
|
||||
$hdr_data .= sprintf "#define %-62s %s", "CCS_LIM_" . (uc ${this{name}} . "_MIN_$arg"), $min . ($min =~ /0x/i ? "" : "U") . "\n";
|
||||
$hdr_data .= sprintf "#define %-62s %s", "CCS_LIM_" . (uc ${this{name}} . "_MAX_$arg"), $max . ($max =~ /0x/i ? "" : "U") . "\n";
|
||||
|
||||
my $h = $this{argparams};
|
||||
|
||||
$h->{$arg} = { "min" => $min,
|
||||
"max" => $max,
|
||||
"elsize" => $elsize =~ /^0x/ ? hex $elsize : $elsize,
|
||||
"discontig" => \@discontig };
|
||||
|
||||
$this{discontig} = $arg if @discontig;
|
||||
|
||||
next if $#{$this{args}} + 1 != scalar keys %{$this{argparams}};
|
||||
|
||||
my $reg_formula = "($this{addr}";
|
||||
my $lim_formula;
|
||||
|
||||
foreach my $arg (@{$this{args}}) {
|
||||
my $d = $h->{$arg}->{discontig};
|
||||
my $times = $h->{$arg}->{elsize} != 1 ?
|
||||
" * " . $h->{$arg}->{elsize} : "";
|
||||
|
||||
if (@$d) {
|
||||
my ($lim, $offset) = split /,/, $d->[0];
|
||||
|
||||
$reg_formula .= " + (($arg) < $lim ? ($arg)$times : $offset + (($arg) - $lim)$times)";
|
||||
} else {
|
||||
$reg_formula .= " + ($arg)$times";
|
||||
}
|
||||
|
||||
$lim_formula .= (defined $lim_formula ? " + " : "") . "($arg)$times";
|
||||
}
|
||||
|
||||
$reg_formula .= ")\n";
|
||||
$lim_formula =~ s/^\(([a-z0-9]+)\)$/$1/i;
|
||||
|
||||
print $H tabconv sprintf("#define %-62s %s", "CCS_R_" . (uc $this{name}) .
|
||||
$this{arglist}, $reg_formula);
|
||||
|
||||
print $H tabconv $hdr_data;
|
||||
undef $hdr_data;
|
||||
|
||||
# Sort arguments in descending order by size
|
||||
@{$this{sorted_args}} = sort {
|
||||
$h->{$a}->{elsize} <= $h->{$b}->{elsize}
|
||||
} @{$this{args}};
|
||||
|
||||
if (defined $this{discontig}) {
|
||||
my $da = $this{argparams}->{$this{discontig}};
|
||||
my ($first_discontig) = split /,/, $da->{discontig}->[0];
|
||||
my $max = $da->{max};
|
||||
|
||||
$da->{max} = $first_discontig - 1;
|
||||
print_args(\%this, "", 0);
|
||||
|
||||
$da->{min} = $da->{max} + 1;
|
||||
$da->{max} = $max;
|
||||
print_args(\%this, $first_discontig, 1);
|
||||
} else {
|
||||
print_args(\%this, "", 0);
|
||||
}
|
||||
|
||||
next unless is_limit_reg $this{base_addr};
|
||||
|
||||
print $LH tabconv sprintf "#define %-63s%s\n",
|
||||
"CCS_L_" . (uc $this{name}) . "_OFFSET(" .
|
||||
(join ", ", @{$this{args}}) . ")", "($lim_formula)";
|
||||
}
|
||||
|
||||
if (! @{$this{args}}) {
|
||||
print $H tabconv($hdr_data);
|
||||
undef $hdr_data;
|
||||
}
|
||||
|
||||
next;
|
||||
}
|
||||
|
||||
my ($name, $addr, @flags) = split /\t+/, $_;
|
||||
my $args = [];
|
||||
|
||||
my $sp;
|
||||
|
||||
($name, $addr, $args) = name_split($name, $addr) if /\(.*\)/;
|
||||
|
||||
$name =~ s/[,\.-]/_/g;
|
||||
|
||||
my $flagstring = "";
|
||||
my $size = elem_size(@flags);
|
||||
$flagstring .= "| CCS_FL_16BIT " if $size eq "2";
|
||||
$flagstring .= "| CCS_FL_32BIT " if $size eq "4";
|
||||
$flagstring .= "| CCS_FL_FLOAT_IREAL " if grep /^float_ireal$/, @flags;
|
||||
$flagstring .= "| CCS_FL_IREAL " if grep /^ireal$/, @flags;
|
||||
$flagstring =~ s/^\| //;
|
||||
$flagstring =~ s/ $//;
|
||||
$flagstring = "($flagstring)" if $flagstring =~ /\|/;
|
||||
my $base_addr = $addr;
|
||||
$addr = "($addr | $flagstring)" if $flagstring ne "";
|
||||
|
||||
my $arglist = @$args ? "(" . (join ", ", @$args) . ")" : "";
|
||||
$hdr_data .= sprintf "#define %-62s %s\n", "CCS_R_" . (uc $name), $addr
|
||||
if !@$args;
|
||||
|
||||
$name =~ s/\(.*//;
|
||||
|
||||
%this = ( name => $name,
|
||||
addr => $addr,
|
||||
base_addr => $base_addr,
|
||||
argparams => {},
|
||||
args => $args,
|
||||
arglist => $arglist,
|
||||
elsize => $size,
|
||||
);
|
||||
|
||||
if (!@$args) {
|
||||
$reglist .= "\t{ CCS_R_" . (uc $name) . ", 1, 0, \"" . (lc $name) . "\", NULL },\n";
|
||||
print $H tabconv $hdr_data;
|
||||
undef $hdr_data;
|
||||
|
||||
print $LC tabconv sprintf "\t{ CCS_R_" . (uc $name) . ", " .
|
||||
$this{elsize} . ", 0, \"$name\" },\n"
|
||||
if is_limit_reg $this{base_addr};
|
||||
}
|
||||
|
||||
print $LH tabconv sprintf "#define %-63s%s\n",
|
||||
"CCS_L_" . (uc $this{name}), $limitcount++
|
||||
if is_limit_reg $this{base_addr};
|
||||
}
|
||||
|
||||
if (defined $A) {
|
||||
print $A $argdescs, $reglist;
|
||||
|
||||
print $A "\t{ 0 }\n";
|
||||
|
||||
print $A "};\n";
|
||||
}
|
||||
|
||||
print $H "\n#endif /* __${uc_header}__ */\n";
|
||||
|
||||
print $LH tabconv sprintf "#define %-63s%s\n", "CCS_L_LAST", $limitcount;
|
||||
|
||||
print $LH "\n#endif /* __${uc_limith}__ */\n";
|
||||
|
||||
print $LC "\t{ 0 } /* Guardian */\n";
|
||||
print $LC "};\n";
|
||||
|
||||
close($R);
|
||||
close($H);
|
||||
close($A) if defined $A;
|
||||
close($LC);
|
||||
close($LH);
|
@ -16108,6 +16108,7 @@ M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
|
||||
F: Documentation/driver-api/media/drivers/ccs/
|
||||
F: drivers/media/i2c/smiapp-pll.c
|
||||
F: drivers/media/i2c/smiapp-pll.h
|
||||
F: drivers/media/i2c/smiapp/
|
||||
|
Loading…
x
Reference in New Issue
Block a user