Commit f1b6c814f70431be638f99bef8404a51c9a87349
1 parent
55dbdd9d56
Exists in
smarc_8mm-imx_v2018.03_4.14.98_2.0.0_ga
and in
4 other branches
MLK-20962: Support legacy full id NAND in SPL
Current SPL code only support ONFI-compatible NAND, porting the code from nand_base.c to support legacy full id NAND chips, such as Toshiba TC58NVG2S0H. Signed-off-by: Han Xu <han.xu@nxp.com> (cherry picked from commit 4086c6b9556acbec2a8748578eb4a9e719ab4ae7)
Showing 2 changed files with 65 additions and 6 deletions Inline Diff
drivers/mtd/nand/Makefile
1 | # | 1 | # |
2 | # (C) Copyright 2006 | 2 | # (C) Copyright 2006 |
3 | # Wolfgang Denk, DENX Software Engineering, wd@denx.de. | 3 | # Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
4 | # | 4 | # |
5 | # SPDX-License-Identifier: GPL-2.0+ | 5 | # SPDX-License-Identifier: GPL-2.0+ |
6 | # | 6 | # |
7 | 7 | ||
8 | ifdef CONFIG_SPL_BUILD | 8 | ifdef CONFIG_SPL_BUILD |
9 | 9 | ||
10 | ifdef CONFIG_SPL_NAND_DRIVERS | 10 | ifdef CONFIG_SPL_NAND_DRIVERS |
11 | NORMAL_DRIVERS=y | 11 | NORMAL_DRIVERS=y |
12 | endif | 12 | endif |
13 | 13 | ||
14 | obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o | 14 | obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o |
15 | obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o | 15 | obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o |
16 | obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o | 16 | obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o |
17 | obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o | 17 | obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o |
18 | obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o | 18 | obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o |
19 | obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o | 19 | obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o |
20 | obj-$(CONFIG_SPL_NAND_INIT) += nand.o | 20 | obj-$(CONFIG_SPL_NAND_INIT) += nand.o |
21 | ifeq ($(CONFIG_SPL_ENV_SUPPORT),y) | 21 | ifeq ($(CONFIG_SPL_ENV_SUPPORT),y) |
22 | obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o | 22 | obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o |
23 | endif | 23 | endif |
24 | 24 | ||
25 | else # not spl | 25 | else # not spl |
26 | 26 | ||
27 | NORMAL_DRIVERS=y | 27 | NORMAL_DRIVERS=y |
28 | 28 | ||
29 | obj-y += nand.o | 29 | obj-y += nand.o |
30 | obj-y += nand_bbt.o | 30 | obj-y += nand_bbt.o |
31 | obj-y += nand_ids.o | 31 | obj-y += nand_ids.o |
32 | obj-y += nand_util.o | 32 | obj-y += nand_util.o |
33 | obj-y += nand_ecc.o | 33 | obj-y += nand_ecc.o |
34 | obj-y += nand_base.o | 34 | obj-y += nand_base.o |
35 | obj-y += nand_timings.o | 35 | obj-y += nand_timings.o |
36 | 36 | ||
37 | endif # not spl | 37 | endif # not spl |
38 | 38 | ||
39 | ifdef NORMAL_DRIVERS | 39 | ifdef NORMAL_DRIVERS |
40 | 40 | ||
41 | obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o | 41 | obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o |
42 | 42 | ||
43 | obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o | 43 | obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o |
44 | obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o | 44 | obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o |
45 | obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o | 45 | obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o |
46 | obj-$(CONFIG_NAND_DENALI) += denali.o | 46 | obj-$(CONFIG_NAND_DENALI) += denali.o |
47 | obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o | 47 | obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o |
48 | obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o | 48 | obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o |
49 | obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o | 49 | obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o |
50 | obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o | 50 | obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o |
51 | obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o | 51 | obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o |
52 | obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o | 52 | obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o |
53 | obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o | 53 | obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o |
54 | obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o | 54 | obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o |
55 | obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o | 55 | obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o |
56 | obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o | 56 | obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o |
57 | obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o | 57 | obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o |
58 | obj-$(CONFIG_NAND_MXC) += mxc_nand.o | 58 | obj-$(CONFIG_NAND_MXC) += mxc_nand.o |
59 | obj-$(CONFIG_NAND_MXS) += mxs_nand.o | 59 | obj-$(CONFIG_NAND_MXS) += mxs_nand.o |
60 | obj-$(CONFIG_NAND_NDFC) += ndfc.o | 60 | obj-$(CONFIG_NAND_NDFC) += ndfc.o |
61 | obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o | 61 | obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o |
62 | obj-$(CONFIG_NAND_SPEAR) += spr_nand.o | 62 | obj-$(CONFIG_NAND_SPEAR) += spr_nand.o |
63 | obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o | 63 | obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o |
64 | obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o | 64 | obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o |
65 | obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o | 65 | obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o |
66 | obj-$(CONFIG_NAND_PLAT) += nand_plat.o | 66 | obj-$(CONFIG_NAND_PLAT) += nand_plat.o |
67 | obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o | 67 | obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o |
68 | obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o | 68 | obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o |
69 | 69 | ||
70 | else # minimal SPL drivers | 70 | else # minimal SPL drivers |
71 | 71 | ||
72 | obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o | 72 | obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o |
73 | obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o | 73 | obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o |
74 | obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o | 74 | obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o |
75 | obj-y += nand_ids.o | ||
75 | obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o | 76 | obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o |
76 | obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o | 77 | obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o |
77 | 78 | ||
78 | endif # drivers | 79 | endif # drivers |
79 | 80 |
drivers/mtd/nand/mxs_nand_spl.c
1 | /* | 1 | /* |
2 | * Copyright (C) 2014 Gateworks Corporation | 2 | * Copyright (C) 2014 Gateworks Corporation |
3 | * Copyright 2019 NXP | ||
3 | * Author: Tim Harvey <tharvey@gateworks.com> | 4 | * Author: Tim Harvey <tharvey@gateworks.com> |
4 | * | 5 | * |
5 | * SPDX-License-Identifier: GPL-2.0+ | 6 | * SPDX-License-Identifier: GPL-2.0+ |
6 | */ | 7 | */ |
7 | #include <common.h> | 8 | #include <common.h> |
8 | #include <nand.h> | 9 | #include <nand.h> |
9 | #include <malloc.h> | 10 | #include <malloc.h> |
11 | #include <linux/mtd/rawnand.h> | ||
10 | 12 | ||
11 | static struct mtd_info *mtd; | 13 | static struct mtd_info *mtd; |
12 | static struct nand_chip nand_chip; | 14 | static struct nand_chip nand_chip; |
13 | 15 | ||
14 | static void mxs_nand_command(struct mtd_info *mtd, unsigned int command, | 16 | static void mxs_nand_command(struct mtd_info *mtd, unsigned int command, |
15 | int column, int page_addr) | 17 | int column, int page_addr) |
16 | { | 18 | { |
17 | register struct nand_chip *chip = mtd_to_nand(mtd); | 19 | register struct nand_chip *chip = mtd_to_nand(mtd); |
18 | u32 timeo, time_start; | 20 | u32 timeo, time_start; |
19 | 21 | ||
20 | /* write out the command to the device */ | 22 | /* write out the command to the device */ |
21 | chip->cmd_ctrl(mtd, command, NAND_CLE); | 23 | chip->cmd_ctrl(mtd, command, NAND_CLE); |
22 | 24 | ||
23 | /* Serially input address */ | 25 | /* Serially input address */ |
24 | if (column != -1) { | 26 | if (column != -1) { |
25 | chip->cmd_ctrl(mtd, column, NAND_ALE); | 27 | chip->cmd_ctrl(mtd, column, NAND_ALE); |
26 | chip->cmd_ctrl(mtd, column >> 8, NAND_ALE); | 28 | chip->cmd_ctrl(mtd, column >> 8, NAND_ALE); |
27 | } | 29 | } |
28 | if (page_addr != -1) { | 30 | if (page_addr != -1) { |
29 | chip->cmd_ctrl(mtd, page_addr, NAND_ALE); | 31 | chip->cmd_ctrl(mtd, page_addr, NAND_ALE); |
30 | chip->cmd_ctrl(mtd, page_addr >> 8, NAND_ALE); | 32 | chip->cmd_ctrl(mtd, page_addr >> 8, NAND_ALE); |
31 | /* One more address cycle for devices > 128MiB */ | 33 | /* One more address cycle for devices > 128MiB */ |
32 | if (chip->chipsize > (128 << 20)) | 34 | if (chip->chipsize > (128 << 20)) |
33 | chip->cmd_ctrl(mtd, page_addr >> 16, NAND_ALE); | 35 | chip->cmd_ctrl(mtd, page_addr >> 16, NAND_ALE); |
34 | } | 36 | } |
35 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); | 37 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); |
36 | 38 | ||
37 | if (command == NAND_CMD_READ0) { | 39 | if (command == NAND_CMD_READ0) { |
38 | chip->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_CLE); | 40 | chip->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_CLE); |
39 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); | 41 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); |
40 | } else if (command == NAND_CMD_RNDOUT) { | 42 | } else if (command == NAND_CMD_RNDOUT) { |
41 | /* No ready / busy check necessary */ | 43 | /* No ready / busy check necessary */ |
42 | chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, | 44 | chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, |
43 | NAND_NCE | NAND_CLE); | 45 | NAND_NCE | NAND_CLE); |
44 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, | 46 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, |
45 | NAND_NCE); | 47 | NAND_NCE); |
46 | } | 48 | } |
47 | 49 | ||
48 | /* wait for nand ready */ | 50 | /* wait for nand ready */ |
49 | ndelay(100); | 51 | ndelay(100); |
50 | timeo = (CONFIG_SYS_HZ * 20) / 1000; | 52 | timeo = (CONFIG_SYS_HZ * 20) / 1000; |
51 | time_start = get_timer(0); | 53 | time_start = get_timer(0); |
52 | while (get_timer(time_start) < timeo) { | 54 | while (get_timer(time_start) < timeo) { |
53 | if (chip->dev_ready(mtd)) | 55 | if (chip->dev_ready(mtd)) |
54 | break; | 56 | break; |
55 | } | 57 | } |
56 | } | 58 | } |
57 | 59 | ||
58 | static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) | 60 | static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) |
59 | { | 61 | { |
60 | int i; | 62 | int i; |
61 | while (len--) { | 63 | while (len--) { |
62 | crc ^= *p++ << 8; | 64 | crc ^= *p++ << 8; |
63 | for (i = 0; i < 8; i++) | 65 | for (i = 0; i < 8; i++) |
64 | crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); | 66 | crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); |
65 | } | 67 | } |
66 | 68 | ||
67 | return crc; | 69 | return crc; |
68 | } | 70 | } |
69 | 71 | ||
70 | /* Parse the Extended Parameter Page. */ | 72 | /* Parse the Extended Parameter Page. */ |
71 | static int nand_flash_detect_ext_param_page(struct mtd_info *mtd, | 73 | static int nand_flash_detect_ext_param_page(struct mtd_info *mtd, |
72 | struct nand_chip *chip, struct nand_onfi_params *p) | 74 | struct nand_chip *chip, struct nand_onfi_params *p) |
73 | { | 75 | { |
74 | struct onfi_ext_param_page *ep; | 76 | struct onfi_ext_param_page *ep; |
75 | struct onfi_ext_section *s; | 77 | struct onfi_ext_section *s; |
76 | struct onfi_ext_ecc_info *ecc; | 78 | struct onfi_ext_ecc_info *ecc; |
77 | uint8_t *cursor; | 79 | uint8_t *cursor; |
78 | int ret = -EINVAL; | 80 | int ret = -EINVAL; |
79 | int len; | 81 | int len; |
80 | int i; | 82 | int i; |
81 | 83 | ||
82 | len = le16_to_cpu(p->ext_param_page_length) * 16; | 84 | len = le16_to_cpu(p->ext_param_page_length) * 16; |
83 | ep = malloc(len); | 85 | ep = malloc(len); |
84 | if (!ep) { | 86 | if (!ep) { |
85 | printf("can't malloc memory 0x%x\n", len); | 87 | printf("can't malloc memory 0x%x\n", len); |
86 | return -ENOMEM; | 88 | return -ENOMEM; |
87 | } | 89 | } |
88 | 90 | ||
89 | /* Send our own NAND_CMD_PARAM. */ | 91 | /* Send our own NAND_CMD_PARAM. */ |
90 | chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); | 92 | chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); |
91 | 93 | ||
92 | /* Use the Change Read Column command to skip the ONFI param pages. */ | 94 | /* Use the Change Read Column command to skip the ONFI param pages. */ |
93 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, | 95 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, |
94 | sizeof(*p) * p->num_of_param_pages , -1); | 96 | sizeof(*p) * p->num_of_param_pages , -1); |
95 | 97 | ||
96 | /* Read out the Extended Parameter Page. */ | 98 | /* Read out the Extended Parameter Page. */ |
97 | chip->read_buf(mtd, (uint8_t *)ep, len); | 99 | chip->read_buf(mtd, (uint8_t *)ep, len); |
98 | if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2) | 100 | if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2) |
99 | != le16_to_cpu(ep->crc))) { | 101 | != le16_to_cpu(ep->crc))) { |
100 | printf("fail in the CRC.\n"); | 102 | printf("fail in the CRC.\n"); |
101 | goto ext_out; | 103 | goto ext_out; |
102 | } | 104 | } |
103 | 105 | ||
104 | /* | 106 | /* |
105 | * Check the signature. | 107 | * Check the signature. |
106 | * Do not strictly follow the ONFI spec, maybe changed in future. | 108 | * Do not strictly follow the ONFI spec, maybe changed in future. |
107 | */ | 109 | */ |
108 | if (strncmp((char *)ep->sig, "EPPS", 4)) { | 110 | if (strncmp((char *)ep->sig, "EPPS", 4)) { |
109 | printf("The signature is invalid.\n"); | 111 | printf("The signature is invalid.\n"); |
110 | goto ext_out; | 112 | goto ext_out; |
111 | } | 113 | } |
112 | 114 | ||
113 | /* find the ECC section. */ | 115 | /* find the ECC section. */ |
114 | cursor = (uint8_t *)(ep + 1); | 116 | cursor = (uint8_t *)(ep + 1); |
115 | for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) { | 117 | for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) { |
116 | s = ep->sections + i; | 118 | s = ep->sections + i; |
117 | if (s->type == ONFI_SECTION_TYPE_2) | 119 | if (s->type == ONFI_SECTION_TYPE_2) |
118 | break; | 120 | break; |
119 | cursor += s->length * 16; | 121 | cursor += s->length * 16; |
120 | } | 122 | } |
121 | if (i == ONFI_EXT_SECTION_MAX) { | 123 | if (i == ONFI_EXT_SECTION_MAX) { |
122 | printf("We can not find the ECC section.\n"); | 124 | printf("We can not find the ECC section.\n"); |
123 | goto ext_out; | 125 | goto ext_out; |
124 | } | 126 | } |
125 | 127 | ||
126 | /* get the info we want. */ | 128 | /* get the info we want. */ |
127 | ecc = (struct onfi_ext_ecc_info *)cursor; | 129 | ecc = (struct onfi_ext_ecc_info *)cursor; |
128 | 130 | ||
129 | if (!ecc->codeword_size) { | 131 | if (!ecc->codeword_size) { |
130 | printf("Invalid codeword size\n"); | 132 | printf("Invalid codeword size\n"); |
131 | goto ext_out; | 133 | goto ext_out; |
132 | } | 134 | } |
133 | 135 | ||
134 | chip->ecc_strength_ds = ecc->ecc_bits; | 136 | chip->ecc_strength_ds = ecc->ecc_bits; |
135 | chip->ecc_step_ds = 1 << ecc->codeword_size; | 137 | chip->ecc_step_ds = 1 << ecc->codeword_size; |
136 | ret = 0; | 138 | ret = 0; |
137 | 139 | ||
138 | ext_out: | 140 | ext_out: |
139 | free(ep); | 141 | free(ep); |
140 | return ret; | 142 | return ret; |
141 | } | 143 | } |
142 | 144 | ||
145 | /* Extract the bits of per cell from the 3rd byte of the extended ID */ | ||
146 | static int nand_get_bits_per_cell(u8 cellinfo) | ||
147 | { | ||
148 | int bits; | ||
143 | 149 | ||
144 | static int mxs_flash_ident(struct mtd_info *mtd) | 150 | bits = cellinfo & NAND_CI_CELLTYPE_MSK; |
151 | bits >>= NAND_CI_CELLTYPE_SHIFT; | ||
152 | return bits + 1; | ||
153 | } | ||
154 | |||
155 | static inline bool is_full_id_nand(struct nand_flash_dev *type) | ||
145 | { | 156 | { |
157 | return type->id_len; | ||
158 | } | ||
159 | |||
160 | static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, | ||
161 | struct nand_flash_dev *type, u8 *id_data, int *busw) | ||
162 | { | ||
163 | if (!strncmp((char *)type->id, (char *)id_data, type->id_len)) { | ||
164 | mtd->writesize = type->pagesize; | ||
165 | mtd->erasesize = type->erasesize; | ||
166 | mtd->oobsize = type->oobsize; | ||
167 | |||
168 | chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]); | ||
169 | chip->chipsize = (uint64_t)type->chipsize << 20; | ||
170 | chip->options |= type->options; | ||
171 | chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); | ||
172 | chip->ecc_step_ds = NAND_ECC_STEP(type); | ||
173 | chip->onfi_timing_mode_default = | ||
174 | type->onfi_timing_mode_default; | ||
175 | |||
176 | *busw = type->options & NAND_BUSWIDTH_16; | ||
177 | |||
178 | if (!mtd->name) | ||
179 | mtd->name = type->name; | ||
180 | |||
181 | return true; | ||
182 | } | ||
183 | return false; | ||
184 | } | ||
185 | |||
186 | static int mxs_flash_ident(struct mtd_info *mtd, struct nand_flash_dev *type) | ||
187 | { | ||
146 | register struct nand_chip *chip = mtd_to_nand(mtd); | 188 | register struct nand_chip *chip = mtd_to_nand(mtd); |
147 | int i, val; | 189 | int i, val; |
148 | u8 mfg_id, dev_id; | 190 | u8 mfg_id, dev_id; |
149 | u8 id_data[8]; | 191 | u8 id_data[8]; |
150 | struct nand_onfi_params *p = &chip->onfi_params; | 192 | struct nand_onfi_params *p = &chip->onfi_params; |
193 | int busw = 0; | ||
151 | 194 | ||
152 | /* Reset the chip */ | 195 | /* Reset the chip */ |
153 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | 196 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); |
154 | 197 | ||
155 | /* Send the command for reading device ID */ | 198 | /* Send the command for reading device ID */ |
156 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | 199 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
157 | 200 | ||
158 | /* Read manufacturer and device IDs */ | 201 | /* Read manufacturer and device IDs */ |
159 | mfg_id = chip->read_byte(mtd); | 202 | mfg_id = chip->read_byte(mtd); |
160 | dev_id = chip->read_byte(mtd); | 203 | dev_id = chip->read_byte(mtd); |
161 | 204 | ||
162 | /* Try again to make sure */ | 205 | /* Try again to make sure */ |
163 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | 206 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
164 | for (i = 0; i < 8; i++) | 207 | for (i = 0; i < 8; i++) |
165 | id_data[i] = chip->read_byte(mtd); | 208 | id_data[i] = chip->read_byte(mtd); |
166 | if (id_data[0] != mfg_id || id_data[1] != dev_id) { | 209 | if (id_data[0] != mfg_id || id_data[1] != dev_id) { |
167 | printf("second ID read did not match"); | 210 | printf("second ID read did not match"); |
168 | return -1; | 211 | return -1; |
169 | } | 212 | } |
170 | debug("0x%02x:0x%02x ", mfg_id, dev_id); | 213 | debug("0x%02x:0x%02x ", mfg_id, dev_id); |
171 | 214 | ||
215 | if (!type) | ||
216 | type = nand_flash_ids; | ||
217 | |||
218 | for (; type->name != NULL; type++) { | ||
219 | if (is_full_id_nand(type)) { | ||
220 | if (find_full_id_nand(mtd, chip, type, id_data, &busw)) | ||
221 | goto ident_done; | ||
222 | } else if (dev_id == type->dev_id) { | ||
223 | break; | ||
224 | } | ||
225 | } | ||
226 | |||
172 | /* read ONFI */ | 227 | /* read ONFI */ |
173 | chip->onfi_version = 0; | 228 | chip->onfi_version = 0; |
174 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); | 229 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); |
175 | if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || | 230 | if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || |
176 | chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') { | 231 | chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') { |
177 | return -2; | 232 | return -2; |
178 | } | 233 | } |
179 | 234 | ||
180 | /* we have ONFI, probe it */ | 235 | /* we have ONFI, probe it */ |
181 | chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); | 236 | chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); |
182 | chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); | 237 | chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); |
183 | mtd->name = p->model; | 238 | mtd->name = p->model; |
184 | mtd->writesize = le32_to_cpu(p->byte_per_page); | 239 | mtd->writesize = le32_to_cpu(p->byte_per_page); |
185 | mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; | 240 | mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; |
186 | mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); | 241 | mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); |
187 | chip->chipsize = le32_to_cpu(p->blocks_per_lun); | 242 | chip->chipsize = le32_to_cpu(p->blocks_per_lun); |
188 | chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; | 243 | chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; |
189 | /* Calculate the address shift from the page size */ | 244 | /* Calculate the address shift from the page size */ |
190 | chip->page_shift = ffs(mtd->writesize) - 1; | 245 | chip->page_shift = ffs(mtd->writesize) - 1; |
191 | chip->phys_erase_shift = ffs(mtd->erasesize) - 1; | 246 | chip->phys_erase_shift = ffs(mtd->erasesize) - 1; |
192 | /* Convert chipsize to number of pages per chip -1 */ | 247 | /* Convert chipsize to number of pages per chip -1 */ |
193 | chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; | 248 | chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; |
194 | chip->badblockbits = 8; | 249 | chip->badblockbits = 8; |
195 | 250 | ||
196 | /* Check version */ | 251 | /* Check version */ |
197 | val = le16_to_cpu(p->revision); | 252 | val = le16_to_cpu(p->revision); |
198 | if (val & (1 << 5)) | 253 | if (val & (1 << 5)) |
199 | chip->onfi_version = 23; | 254 | chip->onfi_version = 23; |
200 | else if (val & (1 << 4)) | 255 | else if (val & (1 << 4)) |
201 | chip->onfi_version = 22; | 256 | chip->onfi_version = 22; |
202 | else if (val & (1 << 3)) | 257 | else if (val & (1 << 3)) |
203 | chip->onfi_version = 21; | 258 | chip->onfi_version = 21; |
204 | else if (val & (1 << 2)) | 259 | else if (val & (1 << 2)) |
205 | chip->onfi_version = 20; | 260 | chip->onfi_version = 20; |
206 | else if (val & (1 << 1)) | 261 | else if (val & (1 << 1)) |
207 | chip->onfi_version = 10; | 262 | chip->onfi_version = 10; |
208 | 263 | ||
209 | if (!chip->onfi_version) { | 264 | if (!chip->onfi_version) { |
210 | printf("unsupported ONFI version: %d\n", val); | 265 | printf("unsupported ONFI version: %d\n", val); |
211 | return 0; | 266 | return 0; |
212 | } | 267 | } |
213 | 268 | ||
214 | if (p->ecc_bits != 0xff) { | 269 | if (p->ecc_bits != 0xff) { |
215 | chip->ecc_strength_ds = p->ecc_bits; | 270 | chip->ecc_strength_ds = p->ecc_bits; |
216 | chip->ecc_step_ds = 512; | 271 | chip->ecc_step_ds = 512; |
217 | } else if (chip->onfi_version >= 21 && | 272 | } else if (chip->onfi_version >= 21 && |
218 | (onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) { | 273 | (onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) { |
219 | 274 | ||
220 | if (nand_flash_detect_ext_param_page(mtd, chip, p)) | 275 | if (nand_flash_detect_ext_param_page(mtd, chip, p)) |
221 | printf("Failed to detect ONFI extended param page\n"); | 276 | printf("Failed to detect ONFI extended param page\n"); |
222 | } else { | 277 | } else { |
223 | printf("Could not retrieve ONFI ECC requirements\n"); | 278 | printf("Could not retrieve ONFI ECC requirements\n"); |
224 | } | 279 | } |
225 | 280 | ||
281 | ident_done: | ||
282 | chip->page_shift = ffs(mtd->writesize) - 1; | ||
283 | chip->phys_erase_shift = ffs(mtd->erasesize) - 1; | ||
226 | debug("ecc_strength_ds %u, ecc_step_ds %u\n", chip->ecc_strength_ds, chip->ecc_step_ds); | 284 | debug("ecc_strength_ds %u, ecc_step_ds %u\n", chip->ecc_strength_ds, chip->ecc_step_ds); |
227 | debug("erasesize=%d (>>%d)\n", mtd->erasesize, chip->phys_erase_shift); | 285 | debug("erasesize=%x (>>%d)\n", mtd->erasesize, chip->phys_erase_shift); |
228 | debug("writesize=%d (>>%d)\n", mtd->writesize, chip->page_shift); | 286 | debug("writesize=%x (>>%d)\n", mtd->writesize, chip->page_shift); |
229 | debug("oobsize=%d\n", mtd->oobsize); | 287 | debug("oobsize=%d\n", mtd->oobsize); |
230 | debug("chipsize=%lld\n", chip->chipsize); | 288 | debug("chipsize=%llx\n", chip->chipsize); |
231 | 289 | ||
232 | return 0; | 290 | return 0; |
233 | } | 291 | } |
234 | 292 | ||
235 | static int mxs_read_page_ecc(struct mtd_info *mtd, void *buf, unsigned int page) | 293 | static int mxs_read_page_ecc(struct mtd_info *mtd, void *buf, unsigned int page) |
236 | { | 294 | { |
237 | register struct nand_chip *chip = mtd_to_nand(mtd); | 295 | register struct nand_chip *chip = mtd_to_nand(mtd); |
238 | int ret; | 296 | int ret; |
239 | 297 | ||
240 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); | 298 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); |
241 | ret = nand_chip.ecc.read_page(mtd, chip, buf, 1, page); | 299 | ret = nand_chip.ecc.read_page(mtd, chip, buf, 1, page); |
242 | if (ret < 0) { | 300 | if (ret < 0) { |
243 | printf("read_page failed %d\n", ret); | 301 | printf("read_page failed %d\n", ret); |
244 | return -1; | 302 | return -1; |
245 | } | 303 | } |
246 | return 0; | 304 | return 0; |
247 | } | 305 | } |
248 | 306 | ||
249 | static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt) | 307 | static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt) |
250 | { | 308 | { |
251 | register struct nand_chip *chip = mtd_to_nand(mtd); | 309 | register struct nand_chip *chip = mtd_to_nand(mtd); |
252 | unsigned int block = offs >> chip->phys_erase_shift; | 310 | unsigned int block = offs >> chip->phys_erase_shift; |
253 | unsigned int page = offs >> chip->page_shift; | 311 | unsigned int page = offs >> chip->page_shift; |
254 | 312 | ||
255 | debug("%s offs=0x%08x block:%d page:%d\n", __func__, (int)offs, block, | 313 | debug("%s offs=0x%08x block:%d page:%d\n", __func__, (int)offs, block, |
256 | page); | 314 | page); |
257 | chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); | 315 | chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); |
258 | memset(chip->oob_poi, 0, mtd->oobsize); | 316 | memset(chip->oob_poi, 0, mtd->oobsize); |
259 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | 317 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
260 | 318 | ||
261 | return chip->oob_poi[0] != 0xff; | 319 | return chip->oob_poi[0] != 0xff; |
262 | } | 320 | } |
263 | 321 | ||
264 | /* setup mtd and nand structs and init mxs_nand driver */ | 322 | /* setup mtd and nand structs and init mxs_nand driver */ |
265 | static int mxs_nand_init(void) | 323 | static int mxs_nand_init(void) |
266 | { | 324 | { |
267 | /* return if already initalized */ | 325 | /* return if already initalized */ |
268 | if (nand_chip.numchips) | 326 | if (nand_chip.numchips) |
269 | return 0; | 327 | return 0; |
270 | 328 | ||
271 | /* init mxs nand driver */ | 329 | /* init mxs nand driver */ |
272 | board_nand_init(&nand_chip); | 330 | board_nand_init(&nand_chip); |
273 | mtd = nand_to_mtd(&nand_chip); | 331 | mtd = nand_to_mtd(&nand_chip); |
274 | /* set mtd functions */ | 332 | /* set mtd functions */ |
275 | nand_chip.cmdfunc = mxs_nand_command; | 333 | nand_chip.cmdfunc = mxs_nand_command; |
276 | nand_chip.numchips = 1; | 334 | nand_chip.numchips = 1; |
277 | 335 | ||
278 | /* identify flash device */ | 336 | /* identify flash device */ |
279 | if (mxs_flash_ident(mtd)) { | 337 | if (mxs_flash_ident(mtd, NULL)) { |
280 | printf("Failed to identify\n"); | 338 | printf("Failed to identify\n"); |
281 | return -1; | 339 | return -1; |
282 | } | 340 | } |
283 | 341 | ||
284 | /* allocate and initialize buffers */ | 342 | /* allocate and initialize buffers */ |
285 | nand_chip.buffers = memalign(ARCH_DMA_MINALIGN, | 343 | nand_chip.buffers = memalign(ARCH_DMA_MINALIGN, |
286 | sizeof(*nand_chip.buffers)); | 344 | sizeof(*nand_chip.buffers)); |
287 | nand_chip.oob_poi = nand_chip.buffers->databuf + mtd->writesize; | 345 | nand_chip.oob_poi = nand_chip.buffers->databuf + mtd->writesize; |
288 | /* setup flash layout (does not scan as we override that) */ | 346 | /* setup flash layout (does not scan as we override that) */ |
289 | mtd->size = nand_chip.chipsize; | 347 | mtd->size = nand_chip.chipsize; |
290 | nand_chip.scan_bbt(mtd); | 348 | nand_chip.scan_bbt(mtd); |
291 | 349 | ||
292 | return 0; | 350 | return 0; |
293 | } | 351 | } |
294 | 352 | ||
295 | int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) | 353 | int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) |
296 | { | 354 | { |
297 | struct nand_chip *chip; | 355 | struct nand_chip *chip; |
298 | unsigned int page; | 356 | unsigned int page; |
299 | unsigned int nand_page_per_block; | 357 | unsigned int nand_page_per_block; |
300 | unsigned int sz = 0; | 358 | unsigned int sz = 0; |
301 | uint8_t *page_buf = NULL; | 359 | uint8_t *page_buf = NULL; |
302 | uint32_t page_off; | 360 | uint32_t page_off; |
303 | 361 | ||
304 | if (mxs_nand_init()) | 362 | if (mxs_nand_init()) |
305 | return -ENODEV; | 363 | return -ENODEV; |
306 | 364 | ||
307 | chip = mtd_to_nand(mtd); | 365 | chip = mtd_to_nand(mtd); |
308 | 366 | ||
309 | page_buf = malloc(mtd->writesize); | 367 | page_buf = malloc(mtd->writesize); |
310 | if (!page_buf) | 368 | if (!page_buf) |
311 | return -ENOMEM; | 369 | return -ENOMEM; |
312 | 370 | ||
313 | page = offs >> chip->page_shift; | 371 | page = offs >> chip->page_shift; |
314 | page_off = offs & (mtd->writesize - 1); | 372 | page_off = offs & (mtd->writesize - 1); |
315 | nand_page_per_block = mtd->erasesize / mtd->writesize; | 373 | nand_page_per_block = mtd->erasesize / mtd->writesize; |
316 | 374 | ||
317 | debug("%s offset:0x%08x len:%d page:%d\n", __func__, offs, size, page); | 375 | debug("%s offset:0x%08x len:%d page:%x\n", __func__, offs, size, page); |
318 | 376 | ||
319 | while (size) { | 377 | while (size) { |
320 | if (mxs_read_page_ecc(mtd, page_buf, page) < 0) | 378 | if (mxs_read_page_ecc(mtd, page_buf, page) < 0) |
321 | return -1; | 379 | return -1; |
322 | 380 | ||
323 | if (size > (mtd->writesize - page_off)) | 381 | if (size > (mtd->writesize - page_off)) |
324 | sz = (mtd->writesize - page_off); | 382 | sz = (mtd->writesize - page_off); |
325 | else | 383 | else |
326 | sz = size; | 384 | sz = size; |
327 | 385 | ||
328 | memcpy(buf, page_buf + page_off, sz); | 386 | memcpy(buf, page_buf + page_off, sz); |
329 | 387 | ||
330 | offs += mtd->writesize; | 388 | offs += mtd->writesize; |
331 | page++; | 389 | page++; |
332 | buf += (mtd->writesize - page_off); | 390 | buf += (mtd->writesize - page_off); |
333 | page_off = 0; | 391 | page_off = 0; |
334 | size -= sz; | 392 | size -= sz; |
335 | 393 | ||
336 | /* | 394 | /* |
337 | * Check if we have crossed a block boundary, and if so | 395 | * Check if we have crossed a block boundary, and if so |
338 | * check for bad block. | 396 | * check for bad block. |
339 | */ | 397 | */ |
340 | if (!(page % nand_page_per_block)) { | 398 | if (!(page % nand_page_per_block)) { |
341 | /* | 399 | /* |
342 | * Yes, new block. See if this block is good. If not, | 400 | * Yes, new block. See if this block is good. If not, |
343 | * loop until we find a good block. | 401 | * loop until we find a good block. |
344 | */ | 402 | */ |
345 | while (is_badblock(mtd, offs, 1)) { | 403 | while (is_badblock(mtd, offs, 1)) { |
346 | page = page + nand_page_per_block; | 404 | page = page + nand_page_per_block; |
347 | /* Check i we've reached the end of flash. */ | 405 | /* Check i we've reached the end of flash. */ |
348 | if (page >= mtd->size >> chip->page_shift) { | 406 | if (page >= mtd->size >> chip->page_shift) { |
349 | free(page_buf); | 407 | free(page_buf); |
350 | return -ENOMEM; | 408 | return -ENOMEM; |
351 | } | 409 | } |
352 | } | 410 | } |
353 | } | 411 | } |
354 | } | 412 | } |
355 | 413 | ||
356 | free(page_buf); | 414 | free(page_buf); |
357 | 415 | ||
358 | return 0; | 416 | return 0; |
359 | } | 417 | } |
360 | 418 | ||
361 | int nand_default_bbt(struct mtd_info *mtd) | 419 | int nand_default_bbt(struct mtd_info *mtd) |
362 | { | 420 | { |
363 | return 0; | 421 | return 0; |
364 | } | 422 | } |
365 | 423 | ||
366 | void nand_init(void) | 424 | void nand_init(void) |
367 | { | 425 | { |
368 | } | 426 | } |
369 | 427 | ||
370 | void nand_deselect(void) | 428 | void nand_deselect(void) |
371 | { | 429 | { |
372 | } | 430 | } |
373 | 431 | ||
374 | 432 |