630 lines
20 KiB
Perl
Executable File
630 lines
20 KiB
Perl
Executable File
#!/usr/local/bin/perl -w
|
||
|
||
# SPDX-License-Identifier: LicenseRef-Unisoc-General-1.0
|
||
|
||
# Copyright (C) 2023 Unisoc, Inc.
|
||
# Author: Liangji.chen <[email protected]>
|
||
# This file is used for create sprd_nand_param.h
|
||
|
||
use File::Basename;
|
||
#use strict;
|
||
my $LOCAL_PATH;
|
||
BEGIN
|
||
{
|
||
$LOCAL_PATH = dirname($0);
|
||
}
|
||
#print "xxx $LOCAL_PATH\n";
|
||
use lib "$LOCAL_PATH/Spreadsheet";
|
||
use lib "$LOCAL_PATH/";
|
||
require 'ParseExcel.pm';
|
||
|
||
#****************************************************************************
|
||
# Customization Field
|
||
#****************************************************************************
|
||
my $DebugPrint = "no";
|
||
my $VersionAndChanglist = "2.0 support autodetect NAND ID and improvement\n";
|
||
my @MemoryDeviceList;
|
||
my $SPRD_NAND_PARAM_H = "sprd_nand_param.h";
|
||
my $MEMORY_DEVICE_LIST_XLS = "vendor/sprd/tools/mcp_gen/mcp.xls";
|
||
my $CONFIG_INI = "";
|
||
|
||
#****************************************************************************
|
||
# Main Thread Field
|
||
#****************************************************************************
|
||
if(@ARGV > 1)
|
||
{
|
||
my $parameters="";
|
||
my $where;
|
||
my $value;
|
||
my $tag;
|
||
for($j = 0;$j<@ARGV;$j++)
|
||
{
|
||
$parameters.=$ARGV[$j];
|
||
$parameters.=" ";
|
||
}
|
||
print "$parameters\n";
|
||
$value = &get_parameter_str($parameters,"-h");
|
||
if(length($value) > 0)
|
||
{
|
||
$SPRD_NAND_PARAM_H = $value;
|
||
print "$SPRD_NAND_PARAM_H\n";
|
||
}
|
||
$value = &get_parameter_str($parameters,"-x");
|
||
if(length($value) > 0)
|
||
{
|
||
$MEMORY_DEVICE_LIST_XLS = $value;
|
||
print "$MEMORY_DEVICE_LIST_XLS\n";
|
||
}
|
||
$value = &get_parameter_str($parameters,"-i");
|
||
if(length($value) > 0)
|
||
{
|
||
$CONFIG_INI = $value;
|
||
print "$CONFIG_INI\n";
|
||
if(! -e $CONFIG_INI){
|
||
#die "$CONFIG_INI not exist\n"
|
||
$CONFIG_INI = "";
|
||
}
|
||
}
|
||
}
|
||
|
||
&ReadNANDExcelFile();
|
||
&GenNANDHeaderFile();
|
||
if($DebugPrint eq "yes"){
|
||
print "nandgen done\n";
|
||
}
|
||
exit 0;
|
||
|
||
|
||
#****************************************************************************
|
||
# Subfunction Field
|
||
#****************************************************************************
|
||
sub ReadNANDExcelFile
|
||
{
|
||
my @all_column=[];
|
||
my $SheetName = "NAND";
|
||
my $parser = Spreadsheet::ParseExcel->new();
|
||
my $Book = $parser->Parse($MEMORY_DEVICE_LIST_XLS);
|
||
my $sheet = $Book->Worksheet($SheetName);
|
||
my %COLUMN_LIST;
|
||
my $tmp;
|
||
my $row;
|
||
my $col;
|
||
|
||
for($col = 0, $row = 0,$tmp = &xls_cell_value($sheet, $row, $col); $tmp; $col++, $tmp = &xls_cell_value($sheet, $row, $col))
|
||
{
|
||
$COLUMN_LIST{$tmp} = $col;
|
||
}
|
||
@all_column=sort (keys(%COLUMN_LIST));
|
||
if($DebugPrint eq "yes"){
|
||
print "@all_column\n";
|
||
}
|
||
|
||
for($row = 1,$tmp = &xls_cell_value($sheet, $row, $COLUMN_LIST{Part_Number});$tmp;$row++,$tmp = &xls_cell_value($sheet, $row, $COLUMN_LIST{Part_Number}))
|
||
{
|
||
foreach $i (@all_column){
|
||
$MemoryDeviceList[$row-1]{$i}=&xls_cell_value($sheet, $row, $COLUMN_LIST{$i});
|
||
}
|
||
}
|
||
|
||
if($DebugPrint eq "yes"){
|
||
print "~~~~~~~~~EXCEL INFO~~~~~~~~~~~\n";
|
||
for($index=0;$index<@MemoryDeviceList;$index++){
|
||
print "index:$index\n";
|
||
foreach $i (@all_column){
|
||
printf ("%-15s:%-20s ",$i,$MemoryDeviceList[$index]->{$i});
|
||
}
|
||
print "\n";
|
||
}
|
||
print "~~~~~~~~~There are $index Nand Chips~~~~~~~~~~~\n";
|
||
}
|
||
}
|
||
|
||
sub GenNANDHeaderFile()
|
||
{
|
||
my %InFileChip;
|
||
my %ChipParamters;
|
||
my $Longest_ID=0;
|
||
my $Chip_count=0;
|
||
my %maker_table_hash;
|
||
my %device_table_hash;
|
||
my $device_table_num=0;
|
||
my @device_table;
|
||
my @p_list;
|
||
my $SpareSize_B_2;
|
||
my $Type0;
|
||
my $Type1;
|
||
my $timing_ace_ns;
|
||
my $timing_rwl_ns;
|
||
my $timing_rwh_ns;
|
||
|
||
if(-e $SPRD_NAND_PARAM_H)
|
||
{
|
||
`chmod 777 $SPRD_NAND_PARAM_H`;
|
||
}
|
||
|
||
if(length($CONFIG_INI) > 0){
|
||
open(FD, "<$CONFIG_INI");
|
||
@p_list=<FD>;
|
||
close FD;
|
||
}
|
||
|
||
for($iter=0;$iter<@MemoryDeviceList;$iter++){
|
||
my $ID_length=0;
|
||
my $ID=$MemoryDeviceList[$iter]->{Nand_ID};
|
||
if(!exists($ChipParamters{$ID})){
|
||
my $partnumber = $MemoryDeviceList[$iter]->{Part_Number};
|
||
if(!&partnumber_is_exist($partnumber,@p_list)){
|
||
print "The chip:$ID $partnumber not selected.\n";
|
||
}
|
||
elsif(length($ID)%2){
|
||
print "The chip:$ID have wrong number,",length($ID),".\n";
|
||
}
|
||
else{
|
||
$ID_length=length($ID)/2-1;
|
||
if($ID_length > $Longest_ID){
|
||
$Longest_ID = $ID_length;
|
||
}
|
||
#print "\$Longest_ID=$Longest_ID\n";
|
||
$InFileChip{$iter}={'ID'=>$ID,'IDLength'=>$ID_length};
|
||
$ChipParamters{$ID}={'BlockSize_KB'=>$MemoryDeviceList[$iter]->{BlockSize_KB},'BlockNum'=>$MemoryDeviceList[$iter]->{BlockNum},
|
||
'PageSize_KB'=>$MemoryDeviceList[$iter]->{PageSize_KB},'SectSize_B'=>$MemoryDeviceList[$iter]->{SectSize_B},
|
||
'BusWidth'=>$MemoryDeviceList[$iter]->{BusWidth},
|
||
'Cycles'=>$MemoryDeviceList[$iter]->{Cycles},'spareSize_B'=>$MemoryDeviceList[$iter]->{spareSize_B},
|
||
'oob_nbadpos'=>$MemoryDeviceList[$iter]->{oob_nBadPos_B},'oob_nbadlen'=>$MemoryDeviceList[$iter]->{oob_nBadLen_B},
|
||
'oob_nEccBits_b'=>$MemoryDeviceList[$iter]->{oob_nEccBits_b},'oob_nEccPos_B'=>$MemoryDeviceList[$iter]->{oob_nEccPos_B},
|
||
'oob_nEccSize_B'=>$MemoryDeviceList[$iter]->{oob_nEccSize_B},'oob_nInfoPos_B'=>$MemoryDeviceList[$iter]->{oob_nInfoPos_B},
|
||
'oob_nInfoSize_B'=>$MemoryDeviceList[$iter]->{oob_nInfoSize_B},'Cell_type'=>$MemoryDeviceList[$iter]->{Cell_type},
|
||
'Intf_type'=>$MemoryDeviceList[$iter]->{Intf_type},'Support_cache'=>$MemoryDeviceList[$iter]->{Support_cache},
|
||
'Plane_sel_bit'=>$MemoryDeviceList[$iter]->{Plane_sel_bit},'Max_IO_Freq'=>$MemoryDeviceList[$iter]->{Max_IO_Freq},
|
||
};
|
||
$Chip_count++;
|
||
}
|
||
}# if(!exists($ChipParamters{$ID}))
|
||
else{#if ID is same,check if parameters is same.
|
||
if($ChipParamters{$ID}->{BlockSize_KB} == $MemoryDeviceList[$iter]->{BlockSize_KB}
|
||
&& $ChipParamters{$ID}->{BlockNum} == $MemoryDeviceList[$iter]->{BlockNum}
|
||
&& $ChipParamters{$ID}->{PageSize_KB} == $MemoryDeviceList[$iter]->{PageSize_KB}
|
||
&& $ChipParamters{$ID}->{SectSize_B} == $MemoryDeviceList[$iter]->{SectSize_B}
|
||
&& $ChipParamters{$ID}->{BusWidth} eq $MemoryDeviceList[$iter]->{BusWidth}
|
||
&& $ChipParamters{$ID}->{spareSize_B} eq $MemoryDeviceList[$iter]->{spareSize_B}
|
||
&& $ChipParamters{$ID}->{oob_nEccBits_b} eq $MemoryDeviceList[$iter]->{oob_nEccBits_b}
|
||
&& $ChipParamters{$ID}->{oob_nEccPos_B} eq $MemoryDeviceList[$iter]->{oob_nEccPos_B}
|
||
&& $ChipParamters{$ID}->{oob_nEccSize_B} eq $MemoryDeviceList[$iter]->{oob_nEccSize_B}
|
||
&& $ChipParamters{$ID}->{oob_nInfoPos_B} eq $MemoryDeviceList[$iter]->{oob_nInfoPos_B}
|
||
&& $ChipParamters{$ID}->{oob_nInfoSize_B} eq $MemoryDeviceList[$iter]->{oob_nInfoSize_B}){
|
||
print "There more than 1 chip have the ID:$MemoryDeviceList[$iter]->{Nand_ID},bypass it\n";
|
||
}
|
||
else{
|
||
print "$ChipParamters{$ID}->{BlockSize_KB},$ChipParamters{$ID}->{BlockNum},$ChipParamters{$ID}->{PageSize_KB},$ChipParamters{$ID}->{SectSize_B},$ChipParamters{$ID}->{BusWidth}";
|
||
print ",$ChipParamters{$ID}->{spareSize_B},$ChipParamters{$ID}->{oob_nEccBits_b},$ChipParamters{$ID}->{oob_nEccPos_B},$ChipParamters{$ID}->{oob_nEccSize_B},$ChipParamters{$ID}->{oob_nInfoPos_B},$ChipParamters{$ID}->{oob_nInfoSize_B}\n";
|
||
print "$MemoryDeviceList[$iter]->{BlockSize_KB},$MemoryDeviceList[$iter]->{BlockNum},$MemoryDeviceList[$iter]->{PageSize_KB},$MemoryDeviceList[$iter]->{SectSize_B},$MemoryDeviceList[$iter]->{BusWidth}";
|
||
print ",$MemoryDeviceList[$iter]->{spareSize_B},$MemoryDeviceList[$iter]->{oob_nEccBits_b},$MemoryDeviceList[$iter]->{oob_nEccPos_B},$MemoryDeviceList[$iter]->{oob_nEccSize_B},$MemoryDeviceList[$iter]->{oob_nInfoPos_B},$MemoryDeviceList[$iter]->{oob_nInfoSize_B}\n";
|
||
die "There more than 1 chip have the ID:$MemoryDeviceList[$iter]->{Nand_ID},but paramters is not same,you should modify the excel!!!!\n";
|
||
}
|
||
}
|
||
}
|
||
print "Chip_count=$Chip_count\n";
|
||
open(FD, ">$SPRD_NAND_PARAM_H") or &error_handler("open $SPRD_NAND_PARAM_H fail\n", __FILE__, __LINE__);
|
||
print FD "#ifndef __SPRD_NAND_PARAM_H__\n#define __SPRD_NAND_PARAM_H__\n\n";
|
||
print FD "#define STATIC_FUNC static __attribute__((unused))\n";
|
||
print FD &sprd_nand_param_h_head();
|
||
|
||
|
||
foreach $it (sort by_index (keys(%InFileChip))){
|
||
my $ID=$InFileChip{$it}->{ID};
|
||
#creat ID arry string
|
||
my @ID_arry=($ID =~ m/([\dA-Fa-f]{2})/gs);
|
||
my $arry_str="{";
|
||
for($i=0;$i<$Longest_ID;$i++){
|
||
if($i<@ID_arry){
|
||
$arry_str.="0x$ID_arry[$i]";
|
||
}else{
|
||
$arry_str.="0x00";
|
||
}
|
||
if($i<$Longest_ID-1){
|
||
$arry_str.=",";
|
||
}
|
||
}
|
||
$maker_table_hash{$ID_arry[0]}=$MemoryDeviceList[$it]->{Vendor};
|
||
$device_table_hash{$ID}={'ID_vendor'=>$ID_arry[0],'ID_type'=>$ID_arry[1],'Vendor'=>$MemoryDeviceList[$it]->{Vendor},'Part_Number'=>$MemoryDeviceList[$it]->{Part_Number},'BusWidth'=>$MemoryDeviceList[$it]->{BusWidth},'Type2'=>$MemoryDeviceList[$it]->{Type2},'BlockSize_KB'=>$MemoryDeviceList[$it]->{BlockSize_KB},'BlockNum'=>$MemoryDeviceList[$it]->{BlockNum}};
|
||
}
|
||
foreach $ID (keys(%device_table_hash)){
|
||
my $find=0;
|
||
for($i=0;$i<$device_table_num;$i++){
|
||
#print "$device_table_hash{$ID}->{Vendor} $device_table[$i]\n";
|
||
if($device_table_hash{$ID}->{Vendor} eq $device_table[$i]){
|
||
$find=1;
|
||
last;
|
||
}
|
||
}
|
||
if($find == 1){
|
||
next;
|
||
}
|
||
$device_table[$device_table_num]=$device_table_hash{$ID}->{Vendor};
|
||
#print "$device_table[$device_table_num]\n";
|
||
$device_table_num++;
|
||
}
|
||
print FD "#ifdef SPRD_NAND_DEVICE_TBL\n";
|
||
for($i=0;$i<@device_table;$i++){
|
||
my $l_maker=lc($device_table[$i]);
|
||
print FD "STATIC_FUNC struct sprd_nand_device "."$l_maker"."_device_table[] = {\n";
|
||
foreach $ID (keys(%device_table_hash)){
|
||
if($device_table_hash{$ID}->{Vendor} eq $device_table[$i]){
|
||
$Type0 = $device_table_hash{$ID}->{BlockSize_KB}*$device_table_hash{$ID}->{BlockNum}*8/(1024*1024);
|
||
$Type1 = substr($device_table_hash{$ID}->{BusWidth},3);
|
||
$Type1 = "x".$Type1;
|
||
print FD "\t{0x$device_table_hash{$ID}->{ID_type},\"$device_table_hash{$ID}->{Part_Number}\",\"$Type0"."Gb,$Type1,$device_table_hash{$ID}->{Type2}\"},\n";
|
||
}
|
||
}
|
||
print FD "\t{0x00,NULL,NULL}\n";
|
||
print FD "};\n\n";
|
||
}
|
||
|
||
print FD "STATIC_FUNC struct sprd_nand_maker maker_table[] = {\n";
|
||
foreach $ID_vendor (keys(%maker_table_hash)){
|
||
my $l_maker=lc($maker_table_hash{$ID_vendor});
|
||
print FD "\t{0x$ID_vendor,\"$maker_table_hash{$ID_vendor}\","."$l_maker"."_device_table},\n";
|
||
}
|
||
print FD "\t{0x00,NULL,NULL}\n";
|
||
print FD "};\n\n";
|
||
|
||
print FD "STATIC_FUNC struct sprd_nand_param sprd_nand_param_table[] = {\n";
|
||
foreach $it (sort by_index (keys(%InFileChip))){
|
||
my $ID=$InFileChip{$it}->{ID};
|
||
#creat ID arry string
|
||
my @ID_arry=($ID =~ m/([\dA-Fa-f]{2})/gs);
|
||
my $arry_str="{";
|
||
for($i=0;$i<$Longest_ID;$i++){
|
||
if($i<@ID_arry){
|
||
$arry_str.="0x$ID_arry[$i]";
|
||
}else{
|
||
$arry_str.="0x00";
|
||
}
|
||
if($i<$Longest_ID-1){
|
||
$arry_str.=",";
|
||
}
|
||
}
|
||
$arry_str.="}";
|
||
if($DebugPrint eq "yes"){
|
||
print "ID=$arry_str\n";
|
||
}
|
||
#print string to file
|
||
$SpareSize_B_2 = $MemoryDeviceList[$it]->{PageSize_KB}*1024/$MemoryDeviceList[$it]->{SectSize_B}*$MemoryDeviceList[$it]->{spareSize_B};
|
||
$timing_ace_ns = ($MemoryDeviceList[$it]->{timing_T_clh} > $MemoryDeviceList[$it]->{timing_T_alh}) ? $MemoryDeviceList[$it]->{timing_T_clh}:$MemoryDeviceList[$it]->{timing_T_alh};
|
||
$timing_rwl_ns = $MemoryDeviceList[$it]->{timing_T_wp};
|
||
$timing_rwh_ns = $MemoryDeviceList[$it]->{timing_T_wh};
|
||
print FD "\t{//$MemoryDeviceList[$it]->{Vendor}\n\t\t$arry_str,0x$ID_arry[0],0x$ID_arry[1], ";
|
||
print FD "\n\t\tSZ_K_BLOCK($MemoryDeviceList[$it]->{BlockSize_KB}),NUM_BLOCK($MemoryDeviceList[$it]->{BlockNum}), SZ_K_PAGE($MemoryDeviceList[$it]->{PageSize_KB}),SZ_B_SECTOR($MemoryDeviceList[$it]->{SectSize_B}),SZ_B_SPARE($SpareSize_B_2),$MemoryDeviceList[$it]->{BusWidth},$MemoryDeviceList[$it]->{Cycles},";
|
||
print FD "\n\t\t{$timing_ace_ns,$timing_rwl_ns,$timing_rwh_ns},";
|
||
print FD "\n\t\t{SZ_B_OOB($MemoryDeviceList[$it]->{spareSize_B}),ECC_BITS($MemoryDeviceList[$it]->{oob_nEccBits_b}),POS_ECC($MemoryDeviceList[$it]->{oob_nEccPos_B}),SZ_ECC($MemoryDeviceList[$it]->{oob_nEccSize_B}),POS_INFO($MemoryDeviceList[$it]->{oob_nInfoPos_B}),SZ_INFO($MemoryDeviceList[$it]->{oob_nInfoSize_B})},";
|
||
print FD "\n\t\tBAD_POS($MemoryDeviceList[$it]->{oob_nBadPos_B}),BAD_LEN($MemoryDeviceList[$it]->{oob_nBadLen_B}),";
|
||
print FD "\n\t\tCELL_TYPE($MemoryDeviceList[$it]->{Cell_type}),INTF_TYPE($MemoryDeviceList[$it]->{Intf_type}),IS_SUPT_CACHE_FUNC($MemoryDeviceList[$it]->{Support_cache}),";
|
||
print FD "\n\t\tPLANE_SEL_BIT($MemoryDeviceList[$it]->{Plane_sel_bit}),MAX_IO_FREQ($MemoryDeviceList[$it]->{Max_IO_Freq}),";
|
||
print FD "\n\t},\n";
|
||
}
|
||
|
||
print FD "\t{\n\t\t{0x00, 0x00, 0x00, 0x00, 0x00},0x00,0x00, ";
|
||
print FD "\n\t\tSZ_K_BLOCK(256),NUM_BLOCK(2048), SZ_K_PAGE(4),SZ_B_SECTOR(512),SZ_B_SPARE(128),0x01,0x05,";
|
||
print FD "\n\t\t{10,21,15},";
|
||
print FD "\n\t\t{SZ_B_OOB(16),ECC_BITS(8),POS_ECC(2),SZ_ECC(14),POS_INFO(0),SZ_INFO(0)},";
|
||
print FD "\n\t\tBAD_POS(2),BAD_LEN(0),";
|
||
print FD "\n\t\tCELL_TYPE(0),INTF_TYPE(0),IS_SUPT_CACHE_FUNC(no),";
|
||
print FD "\n\t\tPLANE_SEL_BIT(-1),MAX_IO_FREQ(0),";
|
||
print FD "\n\t}\n";
|
||
print FD "};\n\n";
|
||
print FD "#endif /* ifdef SPRD_NAND_DEVICE_TBL */\n";
|
||
#print FD &sprd_nand_param_h_fuction();
|
||
print FD "#endif\n";
|
||
close FD;
|
||
}
|
||
|
||
|
||
#****************************************************************************************
|
||
# subroutine: xls_cell_value
|
||
# return: Excel cell value no matter it's in merge area or not, and in windows or not
|
||
# input: $Sheet: Specified Excel Sheet
|
||
# input: $row: Specified row number
|
||
# input: $col: Specified column number
|
||
#****************************************************************************************
|
||
sub xls_cell_value()
|
||
{
|
||
my($Sheet, $row, $col) = @_;
|
||
my $cell = $Sheet->get_cell($row, $col);
|
||
if (defined $cell)
|
||
{
|
||
return $cell->Value();
|
||
} else
|
||
{
|
||
print "$Sheet: row=$row, col=$col undefined\n";
|
||
return;
|
||
}
|
||
}
|
||
|
||
sub partnumber_is_exist()
|
||
{
|
||
my($partnumber, @p_list) = @_;
|
||
my $where;
|
||
#print "$partnumber\n";
|
||
if(@p_list < 1){
|
||
#no mcp_config.ini,so select all
|
||
return 1;
|
||
}
|
||
foreach $it (@p_list){
|
||
chomp($it);
|
||
$it =~ s/^\s+//g;
|
||
$where = index($it,"\#");
|
||
if($where == 0){
|
||
#print "bypass $it\n";
|
||
}
|
||
else{
|
||
if($partnumber eq $it){
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
sub get_parameter_str()
|
||
{
|
||
my($parameters, $tag) = @_;
|
||
my $where;
|
||
my $ret;
|
||
$where=index($parameters,$tag);
|
||
if($where >= 0)
|
||
{
|
||
#bypass "-s ","-h ",and etc
|
||
$ret=substr($parameters,$where+3);
|
||
$where=index($ret," ");
|
||
if($where >= 0)
|
||
{
|
||
$ret=substr($ret,0,$where);
|
||
}
|
||
return $ret;
|
||
}
|
||
return "";
|
||
}
|
||
|
||
#****************************************************************************
|
||
# subroutine: error_handler
|
||
# input: $error_msg: error message
|
||
#****************************************************************************
|
||
sub error_handler()
|
||
{
|
||
my($error_msg, $file, $line_no) = @_;
|
||
my $final_error_msg = "NandGen ERROR: $error_msg at $file line $line_no\n";
|
||
print $final_error_msg;
|
||
die $final_error_msg;
|
||
}
|
||
|
||
sub by_index
|
||
{$a<=>$b}
|
||
|
||
sub sprd_nand_param_h_head()
|
||
{
|
||
my $template = <<"__TEMPLATE";
|
||
#define yes 1
|
||
#define no 0
|
||
#define NAND_MAX_ID_LEN 5
|
||
|
||
#define BW_08 0x00
|
||
#define BW_16 0x01
|
||
|
||
#define CYCLES_3 0x03
|
||
#define CYCLES_4 0x04
|
||
#define CYCLES_5 0x05
|
||
|
||
#define NUM_BLOCK(n) (n)
|
||
|
||
#define SZ_K_BLOCK(n) (n * 1024)
|
||
#define SZ_K_PAGE(n) (n * 1024)
|
||
|
||
#define SZ_B_BLOCK(n) (n)
|
||
#define SZ_B_PAGE(n) (n)
|
||
|
||
#define SZ_B_SPARE(n) (n)
|
||
#define SZ_B_OOB(n) (n)
|
||
#define SZ_B_SECTOR(n) (n)
|
||
|
||
#define BAD_LEN(n) (n)
|
||
#define BAD_POS(n) (n)
|
||
|
||
#define ECC_BITS(n) (n)
|
||
|
||
#define SZ_ECC(n) (n)
|
||
#define POS_ECC(n) (n)
|
||
#define SZ_INFO(n) (n)
|
||
#define POS_INFO(n) (n)
|
||
#define PLANE_SEL_BIT(n) (n) /* bit for plane select */
|
||
#define IS_SUPT_CACHE_FUNC(n) (n) /* 0:not support cache function 1: support cache function */
|
||
#define INTF_TYPE(n) (n)
|
||
#define CELL_TYPE(n) (n)
|
||
#define CALC_ECC_SIZE(n) ((14 * (n) + 7) / 8)
|
||
#define MAX_IO_FREQ(n) (n)
|
||
|
||
struct sprd_nand_device {
|
||
uint8_t id_device;
|
||
char* p_name;
|
||
char* p_type;
|
||
};
|
||
|
||
struct sprd_nand_maker {
|
||
uint8_t idmaker;
|
||
char* p_name;
|
||
struct sprd_nand_device* p_devtab;
|
||
};
|
||
|
||
struct sprd_nand_oob {
|
||
uint16_t oob_size; /* 16 */
|
||
uint8_t ecc_bits;
|
||
uint16_t ecc_pos;
|
||
uint16_t ecc_size; /* 4 */
|
||
uint16_t info_pos;
|
||
uint16_t info_size;
|
||
};
|
||
|
||
struct sprd_nand_timing {
|
||
uint8_t ace_ns; /* ALE, CLE end of delay timing, unit: ns */
|
||
uint8_t rwl_ns; /* WE, RE, IO, pulse timing, unit: ns */
|
||
uint8_t rwh_ns; /* WE, RE, IO, high hold timing, unit: ns */
|
||
};
|
||
|
||
struct sprd_nand_param {
|
||
uint8_t id[NAND_MAX_ID_LEN];
|
||
uint8_t idmaker;
|
||
uint8_t id_device;
|
||
uint32_t blk_size; /* 256K */
|
||
uint32_t blk_num;
|
||
uint32_t page_size; /* 4K */
|
||
uint16_t nsect_size; /* 512 */
|
||
uint16_t nspare_size;
|
||
uint8_t nbus_width;
|
||
uint8_t ncycles;
|
||
struct sprd_nand_timing s_timing;
|
||
struct sprd_nand_oob s_oob;
|
||
uint8_t oob_bad_pos;
|
||
uint8_t oob_bad_len;
|
||
uint8_t cell_type;
|
||
uint8_t intf_type;
|
||
uint8_t supt_cache_func;
|
||
int plane_sel_bit;
|
||
uint32_t max_io_freq;
|
||
};
|
||
|
||
__TEMPLATE
|
||
|
||
return $template;
|
||
}
|
||
|
||
sub sprd_nand_param_h_fuction()
|
||
{
|
||
my $template_fuction = <<"__TEMPLATE";
|
||
print FD "#ifdef SPRD_NAND_DEVICE_TBL\n";
|
||
STATIC_FUNC struct sprd_nand_maker* __FindMaker(uint8_t idmaker) {
|
||
struct sprd_nand_maker* pmaker = maker_table;
|
||
|
||
while (pmaker->idmaker != 0) {
|
||
if(pmaker->idmaker == idmaker) {
|
||
return pmaker;
|
||
}
|
||
pmaker++;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
STATIC_FUNC struct sprd_nand_device* __FindDevice(struct sprd_nand_maker* pmaker, uint8_t id_device) {
|
||
struct sprd_nand_device* pdevice = pmaker->p_devtab;
|
||
|
||
while (pdevice->id_device != 0) {
|
||
if(pdevice->id_device == id_device) {
|
||
return pdevice;
|
||
}
|
||
pdevice++;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
STATIC_FUNC void __PrintNandInfo(struct sprd_nand_param* p) {
|
||
struct sprd_nand_device* pdevice;
|
||
struct sprd_nand_maker* pmaker;
|
||
|
||
DPRINT("%s\\n", __func__);
|
||
|
||
pmaker = __FindMaker(p->idmaker);
|
||
pdevice = __FindDevice(pmaker, p->id_device);
|
||
|
||
DPRINT("device is %s:%s\\n", pmaker->p_name, pdevice->p_name);
|
||
DPRINT("block size is %d\\n", p->blk_size);
|
||
DPRINT("page size is %d\\n", p->page_size);
|
||
DPRINT("spare size is %d\\n", p->nspare_size);
|
||
DPRINT("eccbits is %d\\n", p->s_oob.ecc_bits);
|
||
}
|
||
|
||
|
||
STATIC_FUNC void __ParseNandParam(uint8_t* id) {
|
||
struct sprd_nand_param* param = sprd_nand_param_table;
|
||
|
||
while(param->idmaker != 0) {
|
||
if ((param->id[0] == id[0]) &&
|
||
(param->id[4] == id[1])) {
|
||
__PrintNandInfo(param);
|
||
return param;
|
||
}
|
||
param++;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
STATIC_FUNC int __SprdCheckNancParam(struct sprd_nand_param* param) {
|
||
struct sprd_nand_device* pdevice;
|
||
struct sprd_nand_maker* pmaker;
|
||
struct sprd_nand_oob* poob = ¶m->s_oob;
|
||
uint8_t sector_num = param->page_size / param->nsect_size;
|
||
|
||
DPRINT("%s\\n", __func__);
|
||
|
||
if (param->idmaker != param->id[0]) {
|
||
DPRINT("%s: id is not match!!!!!!!!!!!!!!!\\n", __func__);
|
||
SPRD_ASSERT(0);
|
||
}
|
||
if (param->id_device != param->id[1]) {
|
||
DPRINT("%s: id is not match!!!!!!!!!!!!!!!\\n", __func__);
|
||
SPRD_ASSERT(0);
|
||
}
|
||
if (poob->oob_size * sector_num > param->nspare_size) {
|
||
DPRINT("%s: OOB size is not match!!!!!!!!!!!!!!!\\n", __func__);
|
||
SPRD_ASSERT(0);
|
||
}
|
||
if (poob->ecc_pos + poob->ecc_size > poob->oob_size) {
|
||
DPRINT("%s: ECC size exceeds the oob!!!!!!!!!!!!!!!\\n", __func__);
|
||
SPRD_ASSERT(0);
|
||
}
|
||
if (CALC_ECC_SIZE(poob->ecc_bits) != poob->ecc_size) {
|
||
DPRINT("%s: ECC size is wrong!!!!!!!!!!!!!!!\\n", __func__);
|
||
SPRD_ASSERT(0);
|
||
}
|
||
if (poob->info_pos + poob->info_size != poob->ecc_pos) {
|
||
DPRINT("%s: Info position is wrong!!!!!!!!!!!!!!!\\n", __func__);
|
||
SPRD_ASSERT(0);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
STATIC_FUNC struct sprd_nand_param* SprdGetNandParam(uint8_t* id) {
|
||
struct sprd_nand_param* param = sprd_nand_param_table;
|
||
int i;
|
||
|
||
DPRINT("%s\\n", __func__);
|
||
|
||
for (i = 0; i < 5; i++) {
|
||
DPRINT("id[%d] is %x\\n", i, id[i]);
|
||
}
|
||
|
||
//__ParseNandParam(id);
|
||
|
||
while(param->idmaker != 0) {
|
||
if ((param->id[0] == id[0]) &&
|
||
(param->id[1] == id[1]) &&
|
||
(param->id[2] == id[2]) &&
|
||
(param->id[3] == id[3]) &&
|
||
(param->id[4] == id[4])) {
|
||
|
||
__PrintNandInfo(param);
|
||
__SprdCheckNancParam(param);
|
||
return param;
|
||
}
|
||
param++;
|
||
}
|
||
DPRINT("Nand params unconfigured, please check it. Halt on booting!!!\\n");
|
||
for(;;) /*relax*/;
|
||
|
||
return NULL;
|
||
}
|
||
print FD "#endif /*ifdef SPRD_NAND_DEVICE_TBL*/\n";
|
||
__TEMPLATE
|
||
|
||
return $template_fuction;
|
||
}
|