226 void nand_init(void)
227 {
228 /*
229 * Init board specific nand support
230 */
231 puts("nand_init \n");
232 nand_info[0].priv = &nand_chip;
233 nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W =
234 (void __iomem *)CONFIG_SYS_NAND_BASE;
235 board_nand_init(&nand_chip);
236
237 if (nand_chip.select_chip)
238 nand_chip.select_chip(&nand_info[0], 0);
239
240 /* NAND chip may require reset after power-on */
241 nand_command(0, 0, 0, NAND_CMD_RESET);
242 puts("nand_init end \n");
243 }
244
233行:给IO赋值CONFIG_SYS_NAND_BASE
235行:board_nand_init
972 /*
973 * Board-specific NAND initialization. The following members of the
974 * argument are board-specific:
975 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
976 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
977 * - cmd_ctrl: hardwarespecific function for accesing control-lines
978 * - waitfunc: hardwarespecific function for accesing device ready/busy line
979 * - ecc.hwctl: function to enable (reset) hardware ecc generator
980 * - ecc.mode: mode of ecc, see defines
981 * - chip_delay: chip dependent delay for transfering data from array to
982 * read regs (tR)
983 * - options: various chip options. They can partly be set to inform
984 * nand_scan about special functionality. See the defines for further
985 * explanation
986 */
987 int board_nand_init(struct nand_chip *nand)
988 {
989 int32_t gpmc_config = 0;
990 int cs = cs_next++;
991 int err = 0;
992 /*
993 * xloader/Uboot's gpmc configuration would have configured GPMC for
994 * nand type of memory. The following logic scans and latches on to the
995 * first CS with NAND type memory.
996 * TBD: need to make this logic generic to handle multiple CS NAND
997 * devices.
998 */
999 puts("board_nand_init start\n");
1000 while (cs < GPMC_MAX_CS) {
1001 /* Check if NAND type is set */
1002 if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
1003 /* Found it!! */
1004 break;
1005 }
1006 cs++;
1007 }
1008 if (cs >= GPMC_MAX_CS) {
1009 printf("nand: error: Unable to find NAND settings in "
1010 "GPMC Configuration - quitting\n");
1011 return -ENODEV;
1012 }
1013 printf("board_nand_init mid %x \n", &gpmc_cfg->cs[cs].config1);
1014 gpmc_config = readl(&gpmc_cfg->config);
1015 /* Disable Write protect */
1016 gpmc_config |= 0x10;
1017 writel(gpmc_config, &gpmc_cfg->config);
1018
1019 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
1020 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
1021 omap_nand_info[cs].control = NULL;
1022 omap_nand_info[cs].cs = cs;
1023 omap_nand_info[cs].ws = wscfg[cs];
1024 nand->priv = &omap_nand_info[cs];
1025 nand->cmd_ctrl = omap_nand_hwcontrol;
1026 nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
1027 nand->chip_delay = 100;
1028 nand->ecc.layout = &omap_ecclayout;
1029
1030 /* configure driver and controller based on NAND device bus-width */
1031 gpmc_config = readl(&gpmc_cfg->cs[cs].config1);
1032 #if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT)
1033 nand->options |= NAND_BUSWIDTH_16;
1034 writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1);
1035 #else
1036 nand->options &= ~NAND_BUSWIDTH_16;
1037 writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1);
1038 #endif
1039 int maf_id,dev_id;
1040 read_nand_id(&maf_id, &dev_id);
1041 printf("+++++++++++++++++++maf_id=0x%x,dev_id=0x%x\n",maf_id,dev_id);
1042 /* select ECC scheme */
1043 #if defined(CONFIG_NAND_OMAP_ECCSCHEME)
1044 // err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME,
1045 // CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
1046 #ifdef CONFIG_SPL_BUILD
1047 err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH16_CODE_HW,
1048 CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
1049 #else
1050 err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW,
1051 CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
1052 #endif
1053 #else
1054 /* pagesize and oobsize are not required to configure sw ecc-scheme */
1055 err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
1056 0, 0);
1057 #endif
1058 if (err)
1059 return err;
1060
1061 #ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
1062 nand->read_buf = omap_nand_read_prefetch;
1063 #else
1064 if (nand->options & NAND_BUSWIDTH_16)
1065 nand->read_buf = nand_read_buf16;
1066 else
1067 nand->read_buf = nand_read_buf;
1068 #endif
1069
1070 nand->dev_ready = omap_dev_ready;
1071 printf("+++++++++++++++++++maf_id=0x%x,dev_id=0x%x\n",maf_id,dev_id);
1072 return 0;
1073 }
1074
990行:这个是赋值。
38 static uint8_t cs_next;
看到cs_next =0;
1000~1007行:选取cs
读取config1值:读取nand flash
1014~1017行:Disable Write protect
接下来就是一些配置
nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
omap_nand_info[cs].control = NULL;
omap_nand_info[cs].cs = cs;
omap_nand_info[cs].ws = wscfg[cs];
nand->priv = &omap_nand_info[cs];
nand->cmd_ctrl = omap_nand_hwcontrol;
nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
nand->chip_delay = 100;
nand->ecc.layout = &omap_ecclayout;
1030~1038行:配置bus宽度
1040读取ID :read_nand_id
55 int read_nand_id(int* maf_id, int* dev_id)
56 {
57 struct nand_chip this;
58 init_nand_chip(&this);
59
60 while (!this.dev_ready(&this))
61 ;
62
63 void (*hwctrl)(struct nand_chip *nand, int cmd,
64 unsigned int ctrl) = this.cmd_ctrl;
65
66 /* Begin command latch cycle */
67 hwctrl(&this, NAND_CMD_RESET, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
68
69 hwctrl(&this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
70 while (!this.dev_ready(&this))
71 ;
72
73 hwctrl(&this, NAND_CMD_READID, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
74
75 /* Set ALE and clear CLE to start address cycle */
76 /* Column address */
77 hwctrl(&this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */
78 hwctrl(&this, 0, NAND_CTRL_ALE); /* A[11:9] */
79 /* Row address */
80 hwctrl(&this, 0, NAND_CTRL_ALE); /* A[19:12] */
81 hwctrl(&this, 0, NAND_CTRL_ALE); /* A[27:20] */
82 #ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
83 /* One more address cycle for devices > 128MiB */
84 hwctrl(&this, 0, NAND_CTRL_ALE); /* A[31:28] */
85 #endif
86 hwctrl(&this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
87
88 *maf_id = readb(this.IO_ADDR_R);
89 *dev_id = readb(this.IO_ADDR_R);
90
91 return 0;
92 }
58行:58 init_nand_chip(&this);
43 static int init_nand_chip(struct nand_chip* nand)
44 {
45 int cs = 0;
46 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
47 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
48 nand->cmd_ctrl = omap_nand_hwcontrol;
49 nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
50 nand->chip_delay = 100;
51 nand->ecc.layout = &omap_ecclayout;
52 nand->dev_ready = omap_spl_dev_ready;
53 }
60行:首先判断dev_ready
9 /*#ifdef CONFIG_SPL_BUILD*/
10 /* Check wait pin as dev ready indicator */
11 static int omap_spl_dev_ready(struct nand_chip *mtd)
12 {
13 return gpmc_cfg->status & (1 << 8);
14 }
15 /*#endif*/ /*
判断读取状态
看是否准备好。
63行:这个ctrl
static void omap_nand_hwcontrol(struct nand_chip* nand, int32_t cmd,
uint32_t ctrl)
{
int cs = 0;
register struct nand_chip *this = nand;
/*
* Point the IO_ADDR to DATA and ADDRESS registers instead
* of chip address
*/
switch (ctrl) {
case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
break;
case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
break;
case NAND_CTRL_CHANGE | NAND_NCE:
this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
break;
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, this->IO_ADDR_W);
}
看下面地址。
总的过程:
第1步:写入reset命令。
等待reset完毕。
第2步:写入READID命令。
写入0列0行地址。
读取id,退出这个函数
接下来
1050 行 err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW,
CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
724 /**
725 * omap_select_ecc_scheme - configures driver for particular ecc-scheme
726 * @nand: NAND chip device structure
727 * @ecc_scheme: ecc scheme to configure
728 * @pagesize: number of main-area bytes per page of NAND device
729 * @oobsize: number of OOB/spare bytes per page of NAND device
730 */
731 static int omap_select_ecc_scheme(struct nand_chip *nand,
732 enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
733 struct omap_nand_info *info = nand->priv;
734 struct nand_ecclayout *ecclayout = &omap_ecclayout;
735 int eccsteps = pagesize / SECTOR_BYTES;
736 int i;
737 printf("ecc_scheme %d pagesize = %x oobsize %x ", ecc_scheme, pagesize,oobsize);
738 switch (ecc_scheme) {
739 case OMAP_ECC_HAM1_CODE_SW:
740 debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n");
741 /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are
742 * initialized in nand_scan_tail(), so just set ecc.mode */
743 info->control = NULL;
744 nand->ecc.mode = NAND_ECC_SOFT;
745 nand->ecc.layout = NULL;
746 nand->ecc.size = 0;
747 break;
748
749 case OMAP_ECC_HAM1_CODE_HW:
750 debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n");
751 /* check ecc-scheme requirements before updating ecc info */
752 if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
753 printf("nand: error: insufficient OOB: require=%d\n", (
754 (3 * eccsteps) + BADBLOCK_MARKER_LENGTH));
755 return -EINVAL;
756 }
757 info->control = NULL;
758 /* populate ecc specific fields */
759 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
760 nand->ecc.mode = NAND_ECC_HW;
761 nand->ecc.strength = 1;
762 nand->ecc.size = SECTOR_BYTES;
763 nand->ecc.bytes = 3;
764 nand->ecc.hwctl = omap_enable_hwecc;
765 nand->ecc.correct = omap_correct_data;
766 nand->ecc.calculate = omap_calculate_ecc;
767 /* define ecc-layout */
768 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
769 for (i = 0; i < ecclayout->eccbytes; i++) {
770 if (nand->options & NAND_BUSWIDTH_16)
771 ecclayout->eccpos[i] = i + 2;
772 else
773 ecclayout->eccpos[i] = i + 1;
774 }
775 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
776 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
777 BADBLOCK_MARKER_LENGTH;
778 break;
779
780 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
781 #ifdef CONFIG_BCH
782 debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
783 /* check ecc-scheme requirements before updating ecc info */
784 if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
785 printf("nand: error: insufficient OOB: require=%d\n", (
786 (13 * eccsteps) + BADBLOCK_MARKER_LENGTH));
787 return -EINVAL;
788 }
789 /* check if BCH S/W library can be used for error detection */
790 info->control = init_bch(13, 8, 0x201b);
791 if (!info->control) {
792 printf("nand: error: could not init_bch()\n");
793 return -ENODEV;
794 }
795 /* populate ecc specific fields */
796 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
797 nand->ecc.mode = NAND_ECC_HW;
798 nand->ecc.strength = 8;
799 nand->ecc.size = SECTOR_BYTES;
800 nand->ecc.bytes = 13;
801 nand->ecc.hwctl = omap_enable_hwecc;
802 nand->ecc.correct = omap_correct_data_bch_sw;
803 nand->ecc.calculate = omap_calculate_ecc;
804 /* define ecc-layout */
805 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
806 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
807 for (i = 1; i < ecclayout->eccbytes; i++) {
808 if (i % nand->ecc.bytes)
809 ecclayout->eccpos[i] =
810 ecclayout->eccpos[i - 1] + 1;
811 else
812 ecclayout->eccpos[i] =
813 ecclayout->eccpos[i - 1] + 2;
814 }
815 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
816 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
817 BADBLOCK_MARKER_LENGTH;
818 break;
819 #else
820 printf("nand: error: CONFIG_BCH required for ECC\n");
821 return -EINVAL;
822 #endif
823
824 case OMAP_ECC_BCH8_CODE_HW:
825 #ifdef CONFIG_NAND_OMAP_ELM
826 debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n");
827 /* check ecc-scheme requirements before updating ecc info */
828 if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
829 printf("nand: error: insufficient OOB: require=%d\n", (
830 (14 * eccsteps) + BADBLOCK_MARKER_LENGTH));
831 return -EINVAL;
832 }
833 /* intialize ELM for ECC error detection */
834 elm_init();
835 info->control = NULL;
836 /* populate ecc specific fields */
837 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
838 nand->ecc.mode = NAND_ECC_HW;
839 nand->ecc.strength = 8;
840 nand->ecc.size = SECTOR_BYTES;
841 nand->ecc.bytes = 14;
842 nand->ecc.hwctl = omap_enable_hwecc;
843 nand->ecc.correct = omap_correct_data_bch;
844 nand->ecc.calculate = omap_calculate_ecc;
845 nand->ecc.read_page = omap_read_page_bch;
846 /* define ecc-layout */
847 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
848 for (i = 0; i < ecclayout->eccbytes; i++)
849 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
850 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
851 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
852 BADBLOCK_MARKER_LENGTH;
853 printf("-------------------------------------\n");
854 printf("ecclayout->eccbytes %d off %d len %d\n",ecclayout->eccbytes,\
855 ecclayout->oobfree[0].offset,ecclayout->oobfree[0].length);
856 printf("ooblen %d \n", oobsize);
857 break;
858 #else
859 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
860 return -EINVAL;
861 #endif
862
863 case OMAP_ECC_BCH16_CODE_HW:
864 #ifdef CONFIG_NAND_OMAP_ELM
865 debug("nand: using OMAP_ECC_BCH16_CODE_HW\n");
866 /* check ecc-scheme requirements before updating ecc info */
867 if ((26 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
868 printf("nand: error: insufficient OOB: require=%d\n", (
869 (26 * eccsteps) + BADBLOCK_MARKER_LENGTH));
870 return -EINVAL;
871 }
872 /* intialize ELM for ECC error detection */
873 elm_init();
874 /* populate ecc specific fields */
875 nand->ecc.mode = NAND_ECC_HW;
876 nand->ecc.size = SECTOR_BYTES;
877 nand->ecc.bytes = 26;
878 nand->ecc.strength = 16;
879 nand->ecc.hwctl = omap_enable_hwecc;
880 nand->ecc.correct = omap_correct_data_bch;
881 nand->ecc.calculate = omap_calculate_ecc;
882 nand->ecc.read_page = omap_read_page_bch;
883 /* define ecc-layout */
884 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
885 for (i = 0; i < ecclayout->eccbytes; i++)
886 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
887 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
888 ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes -
889 BADBLOCK_MARKER_LENGTH;
890 break;
891 #else
892 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
893 return -EINVAL;
894 #endif
895 default:
896 debug("nand: error: ecc scheme not enabled or supported\n");
897 return -EINVAL;
898 }
899
900 /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */
901 if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW)
902 nand->ecc.layout = ecclayout;
903
904 info->ecc_scheme = ecc_scheme;
905 return 0;
906 }
907
根据传:入参数OMAP_ECC_BCH8_CODE_HW运行
834行:初始化elm
/**
* elm_reset - Do a soft reset of ELM
*
* Perform a soft reset of ELM and return after reset is done.
*/
void elm_reset(void)
{
/* initiate reset */
writel((readl(&elm_cfg->sysconfig) | ELM_SYSCONFIG_SOFTRESET),
&elm_cfg->sysconfig);
/* wait for reset complete and normal operation */
while ((readl(&elm_cfg->sysstatus) & ELM_SYSSTATUS_RESETDONE) !=
ELM_SYSSTATUS_RESETDONE)
;
}
/**
* elm_init - Initialize ELM module
*
* Initialize ELM support. Currently it does only base address init
* and ELM reset.
*/
void elm_init(void)
{
elm_cfg = (struct elm *)ELM_BASE;
elm_reset();
}
接下来:
nand->ecc.strength = 8;
nand->ecc.size = SECTOR_BYTES;//每个扇区512字节
nand->ecc.bytes = 14;//每个扇区的oob占用字节
接下来对读取一页的数据分析:
nand_read_page
122 static int nand_read_page(int block, int page, void *dst)
123 {
124 struct nand_chip *this = nand_info[0].priv;
125 u_char ecc_calc[ECCTOTAL];
126 u_char ecc_code[ECCTOTAL];
127 u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
128 int i, j;
129 int eccsize = CONFIG_SYS_NAND_ECCSIZE; //512
130 int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
131 int eccsteps = ECCSTEPS;//8
132 uint8_t *p = dst;
133 uint32_t data_pos = 0;
134 uint8_t *oob = &oob_data[0] + nand_ecc_pos[0];
135 uint32_t oob_pos = eccsize * eccsteps + nand_ecc_pos[0];
136
137 nand_command(block, page, 0, NAND_CMD_READ0);
138 // printf("nand_read_page =================\n");
139 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
140 this->ecc.hwctl(&nand_info[0], NAND_ECC_READ);
141 nand_command(block, page, data_pos, NAND_CMD_RNDOUT);
142
143
144 this->read_buf(&nand_info[0], p, eccsize);
145
146
147
148 nand_command(block, page, oob_pos, NAND_CMD_RNDOUT);
149
150 this->read_buf(&nand_info[0], oob, eccbytes);
151 this->ecc.calculate(&nand_info[0], p, &ecc_calc[i]);
152
153 data_pos += eccsize;
154 oob_pos += eccbytes;
155 oob += eccbytes;
156 }
157 // printf("nand_read_page end=================\n");
158 /* Pick the ECC bytes out of the oob data */
159 for (i = 0; i < ECCTOTAL; i++)
160 ecc_code[i] = oob_data[nand_ecc_pos[i]];
161
162 eccsteps = ECCSTEPS;
163 p = dst;
164
165 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
166 /* No chance to do something with the possible error message
167 * from correct_data(). We just hope that all possible errors
168 * are corrected by this routine.
169 */
170 this->ecc.correct(&nand_info[0], p, &ecc_code[i], &ecc_calc[i]);
171 }
172
173 return 0;
174 }
175
139~156行:循环8次使用随机读取命令读取数据。
对于每个扇区:首先使用随机读取命令读取512个字节,然后位置增加512,然后使用随机读取命令读取oob,oob第一次在页尾,读取26个字节,然后位置增加26,就这样读取数据。
还有计算oob就是读取elm计算后的16字节赋给计算的值。
165行循环:接下来就是计算nand是否读取正确。配置lem的type 为BCH8,计算和比较