630 lines
20 KiB
Perl
630 lines
20 KiB
Perl
#!/usr/local/bin/perl -w
|
||||
|
|
|
|||
|
|
# SPDX-License-Identifier: LicenseRef-Unisoc-General-1.0
|
|||
|
|
|
|||
|
|
# Copyright (C) 2023 Unisoc, Inc.
|
|||
|
|
# Author: Liangji.chen <liangji.chen@unisoc.com>
|
|||
|
|
# 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;
|
|||
|
|
}
|