1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Freescale i.MX28 image generator
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
5*4882a593Smuzhiyun * on behalf of DENX Software Engineering GmbH
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <fcntl.h>
11*4882a593Smuzhiyun #include <sys/stat.h>
12*4882a593Smuzhiyun #include <sys/types.h>
13*4882a593Smuzhiyun #include <unistd.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include "compiler.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /* Taken from <linux/kernel.h> */
18*4882a593Smuzhiyun #define __round_mask(x, y) ((__typeof__(x))((y)-1))
19*4882a593Smuzhiyun #define round_down(x, y) ((x) & ~__round_mask(x, y))
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /*
22*4882a593Smuzhiyun * Default BCB layout.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * TWEAK this if you have blown any OCOTP fuses.
25*4882a593Smuzhiyun */
26*4882a593Smuzhiyun #define STRIDE_PAGES 64
27*4882a593Smuzhiyun #define STRIDE_COUNT 4
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /*
30*4882a593Smuzhiyun * Layout for 256Mb big NAND with 2048b page size, 64b OOB size and
31*4882a593Smuzhiyun * 128kb erase size.
32*4882a593Smuzhiyun *
33*4882a593Smuzhiyun * TWEAK this if you have different kind of NAND chip.
34*4882a593Smuzhiyun */
35*4882a593Smuzhiyun static uint32_t nand_writesize = 2048;
36*4882a593Smuzhiyun static uint32_t nand_oobsize = 64;
37*4882a593Smuzhiyun static uint32_t nand_erasesize = 128 * 1024;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /*
40*4882a593Smuzhiyun * Sector on which the SigmaTel boot partition (0x53) starts.
41*4882a593Smuzhiyun */
42*4882a593Smuzhiyun static uint32_t sd_sector = 2048;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun * Each of the U-Boot bootstreams is at maximum 1MB big.
46*4882a593Smuzhiyun *
47*4882a593Smuzhiyun * TWEAK this if, for some wild reason, you need to boot bigger image.
48*4882a593Smuzhiyun */
49*4882a593Smuzhiyun #define MAX_BOOTSTREAM_SIZE (1 * 1024 * 1024)
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* i.MX28 NAND controller-specific constants. DO NOT TWEAK! */
52*4882a593Smuzhiyun #define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
53*4882a593Smuzhiyun #define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512
54*4882a593Smuzhiyun #define MXS_NAND_METADATA_SIZE 10
55*4882a593Smuzhiyun #define MXS_NAND_BITS_PER_ECC_LEVEL 13
56*4882a593Smuzhiyun #define MXS_NAND_COMMAND_BUFFER_SIZE 32
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun struct mx28_nand_fcb {
59*4882a593Smuzhiyun uint32_t checksum;
60*4882a593Smuzhiyun uint32_t fingerprint;
61*4882a593Smuzhiyun uint32_t version;
62*4882a593Smuzhiyun struct {
63*4882a593Smuzhiyun uint8_t data_setup;
64*4882a593Smuzhiyun uint8_t data_hold;
65*4882a593Smuzhiyun uint8_t address_setup;
66*4882a593Smuzhiyun uint8_t dsample_time;
67*4882a593Smuzhiyun uint8_t nand_timing_state;
68*4882a593Smuzhiyun uint8_t rea;
69*4882a593Smuzhiyun uint8_t rloh;
70*4882a593Smuzhiyun uint8_t rhoh;
71*4882a593Smuzhiyun } timing;
72*4882a593Smuzhiyun uint32_t page_data_size;
73*4882a593Smuzhiyun uint32_t total_page_size;
74*4882a593Smuzhiyun uint32_t sectors_per_block;
75*4882a593Smuzhiyun uint32_t number_of_nands; /* Ignored */
76*4882a593Smuzhiyun uint32_t total_internal_die; /* Ignored */
77*4882a593Smuzhiyun uint32_t cell_type; /* Ignored */
78*4882a593Smuzhiyun uint32_t ecc_block_n_ecc_type;
79*4882a593Smuzhiyun uint32_t ecc_block_0_size;
80*4882a593Smuzhiyun uint32_t ecc_block_n_size;
81*4882a593Smuzhiyun uint32_t ecc_block_0_ecc_type;
82*4882a593Smuzhiyun uint32_t metadata_bytes;
83*4882a593Smuzhiyun uint32_t num_ecc_blocks_per_page;
84*4882a593Smuzhiyun uint32_t ecc_block_n_ecc_level_sdk; /* Ignored */
85*4882a593Smuzhiyun uint32_t ecc_block_0_size_sdk; /* Ignored */
86*4882a593Smuzhiyun uint32_t ecc_block_n_size_sdk; /* Ignored */
87*4882a593Smuzhiyun uint32_t ecc_block_0_ecc_level_sdk; /* Ignored */
88*4882a593Smuzhiyun uint32_t num_ecc_blocks_per_page_sdk; /* Ignored */
89*4882a593Smuzhiyun uint32_t metadata_bytes_sdk; /* Ignored */
90*4882a593Smuzhiyun uint32_t erase_threshold;
91*4882a593Smuzhiyun uint32_t boot_patch;
92*4882a593Smuzhiyun uint32_t patch_sectors;
93*4882a593Smuzhiyun uint32_t firmware1_starting_sector;
94*4882a593Smuzhiyun uint32_t firmware2_starting_sector;
95*4882a593Smuzhiyun uint32_t sectors_in_firmware1;
96*4882a593Smuzhiyun uint32_t sectors_in_firmware2;
97*4882a593Smuzhiyun uint32_t dbbt_search_area_start_address;
98*4882a593Smuzhiyun uint32_t badblock_marker_byte;
99*4882a593Smuzhiyun uint32_t badblock_marker_start_bit;
100*4882a593Smuzhiyun uint32_t bb_marker_physical_offset;
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun struct mx28_nand_dbbt {
104*4882a593Smuzhiyun uint32_t checksum;
105*4882a593Smuzhiyun uint32_t fingerprint;
106*4882a593Smuzhiyun uint32_t version;
107*4882a593Smuzhiyun uint32_t number_bb;
108*4882a593Smuzhiyun uint32_t number_2k_pages_bb;
109*4882a593Smuzhiyun };
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun struct mx28_nand_bbt {
112*4882a593Smuzhiyun uint32_t nand;
113*4882a593Smuzhiyun uint32_t number_bb;
114*4882a593Smuzhiyun uint32_t badblock[510];
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun struct mx28_sd_drive_info {
118*4882a593Smuzhiyun uint32_t chip_num;
119*4882a593Smuzhiyun uint32_t drive_type;
120*4882a593Smuzhiyun uint32_t tag;
121*4882a593Smuzhiyun uint32_t first_sector_number;
122*4882a593Smuzhiyun uint32_t sector_count;
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun struct mx28_sd_config_block {
126*4882a593Smuzhiyun uint32_t signature;
127*4882a593Smuzhiyun uint32_t primary_boot_tag;
128*4882a593Smuzhiyun uint32_t secondary_boot_tag;
129*4882a593Smuzhiyun uint32_t num_copies;
130*4882a593Smuzhiyun struct mx28_sd_drive_info drv_info[1];
131*4882a593Smuzhiyun };
132*4882a593Smuzhiyun
mx28_nand_ecc_chunk_cnt(uint32_t page_data_size)133*4882a593Smuzhiyun static inline uint32_t mx28_nand_ecc_chunk_cnt(uint32_t page_data_size)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun return page_data_size / MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
mx28_nand_ecc_size_in_bits(uint32_t ecc_strength)138*4882a593Smuzhiyun static inline uint32_t mx28_nand_ecc_size_in_bits(uint32_t ecc_strength)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun return ecc_strength * MXS_NAND_BITS_PER_ECC_LEVEL;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
mx28_nand_get_ecc_strength(uint32_t page_data_size,uint32_t page_oob_size)143*4882a593Smuzhiyun static inline uint32_t mx28_nand_get_ecc_strength(uint32_t page_data_size,
144*4882a593Smuzhiyun uint32_t page_oob_size)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun int ecc_strength;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun /*
149*4882a593Smuzhiyun * Determine the ECC layout with the formula:
150*4882a593Smuzhiyun * ECC bits per chunk = (total page spare data bits) /
151*4882a593Smuzhiyun * (bits per ECC level) / (chunks per page)
152*4882a593Smuzhiyun * where:
153*4882a593Smuzhiyun * total page spare data bits =
154*4882a593Smuzhiyun * (page oob size - meta data size) * (bits per byte)
155*4882a593Smuzhiyun */
156*4882a593Smuzhiyun ecc_strength = ((page_oob_size - MXS_NAND_METADATA_SIZE) * 8)
157*4882a593Smuzhiyun / (MXS_NAND_BITS_PER_ECC_LEVEL *
158*4882a593Smuzhiyun mx28_nand_ecc_chunk_cnt(page_data_size));
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun return round_down(ecc_strength, 2);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
mx28_nand_get_mark_offset(uint32_t page_data_size,uint32_t ecc_strength)163*4882a593Smuzhiyun static inline uint32_t mx28_nand_get_mark_offset(uint32_t page_data_size,
164*4882a593Smuzhiyun uint32_t ecc_strength)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun uint32_t chunk_data_size_in_bits;
167*4882a593Smuzhiyun uint32_t chunk_ecc_size_in_bits;
168*4882a593Smuzhiyun uint32_t chunk_total_size_in_bits;
169*4882a593Smuzhiyun uint32_t block_mark_chunk_number;
170*4882a593Smuzhiyun uint32_t block_mark_chunk_bit_offset;
171*4882a593Smuzhiyun uint32_t block_mark_bit_offset;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8;
174*4882a593Smuzhiyun chunk_ecc_size_in_bits = mx28_nand_ecc_size_in_bits(ecc_strength);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun chunk_total_size_in_bits =
177*4882a593Smuzhiyun chunk_data_size_in_bits + chunk_ecc_size_in_bits;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* Compute the bit offset of the block mark within the physical page. */
180*4882a593Smuzhiyun block_mark_bit_offset = page_data_size * 8;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* Subtract the metadata bits. */
183*4882a593Smuzhiyun block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun /*
186*4882a593Smuzhiyun * Compute the chunk number (starting at zero) in which the block mark
187*4882a593Smuzhiyun * appears.
188*4882a593Smuzhiyun */
189*4882a593Smuzhiyun block_mark_chunk_number =
190*4882a593Smuzhiyun block_mark_bit_offset / chunk_total_size_in_bits;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /*
193*4882a593Smuzhiyun * Compute the bit offset of the block mark within its chunk, and
194*4882a593Smuzhiyun * validate it.
195*4882a593Smuzhiyun */
196*4882a593Smuzhiyun block_mark_chunk_bit_offset = block_mark_bit_offset -
197*4882a593Smuzhiyun (block_mark_chunk_number * chunk_total_size_in_bits);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (block_mark_chunk_bit_offset > chunk_data_size_in_bits)
200*4882a593Smuzhiyun return 1;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun /*
203*4882a593Smuzhiyun * Now that we know the chunk number in which the block mark appears,
204*4882a593Smuzhiyun * we can subtract all the ECC bits that appear before it.
205*4882a593Smuzhiyun */
206*4882a593Smuzhiyun block_mark_bit_offset -=
207*4882a593Smuzhiyun block_mark_chunk_number * chunk_ecc_size_in_bits;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun return block_mark_bit_offset;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
mx28_nand_mark_byte_offset(void)212*4882a593Smuzhiyun static inline uint32_t mx28_nand_mark_byte_offset(void)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun uint32_t ecc_strength;
215*4882a593Smuzhiyun ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
216*4882a593Smuzhiyun return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) >> 3;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
mx28_nand_mark_bit_offset(void)219*4882a593Smuzhiyun static inline uint32_t mx28_nand_mark_bit_offset(void)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun uint32_t ecc_strength;
222*4882a593Smuzhiyun ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
223*4882a593Smuzhiyun return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) & 0x7;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
mx28_nand_block_csum(uint8_t * block,uint32_t size)226*4882a593Smuzhiyun static uint32_t mx28_nand_block_csum(uint8_t *block, uint32_t size)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun uint32_t csum = 0;
229*4882a593Smuzhiyun int i;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun for (i = 0; i < size; i++)
232*4882a593Smuzhiyun csum += block[i];
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun return csum ^ 0xffffffff;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
mx28_nand_get_fcb(uint32_t size)237*4882a593Smuzhiyun static struct mx28_nand_fcb *mx28_nand_get_fcb(uint32_t size)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun struct mx28_nand_fcb *fcb;
240*4882a593Smuzhiyun uint32_t bcb_size_bytes;
241*4882a593Smuzhiyun uint32_t stride_size_bytes;
242*4882a593Smuzhiyun uint32_t bootstream_size_pages;
243*4882a593Smuzhiyun uint32_t fw1_start_page;
244*4882a593Smuzhiyun uint32_t fw2_start_page;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun fcb = malloc(nand_writesize);
247*4882a593Smuzhiyun if (!fcb) {
248*4882a593Smuzhiyun printf("MX28 NAND: Unable to allocate FCB\n");
249*4882a593Smuzhiyun return NULL;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun memset(fcb, 0, nand_writesize);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun fcb->fingerprint = 0x20424346;
255*4882a593Smuzhiyun fcb->version = 0x01000000;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /*
258*4882a593Smuzhiyun * FIXME: These here are default values as found in kobs-ng. We should
259*4882a593Smuzhiyun * probably retrieve the data from NAND or something.
260*4882a593Smuzhiyun */
261*4882a593Smuzhiyun fcb->timing.data_setup = 80;
262*4882a593Smuzhiyun fcb->timing.data_hold = 60;
263*4882a593Smuzhiyun fcb->timing.address_setup = 25;
264*4882a593Smuzhiyun fcb->timing.dsample_time = 6;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun fcb->page_data_size = nand_writesize;
267*4882a593Smuzhiyun fcb->total_page_size = nand_writesize + nand_oobsize;
268*4882a593Smuzhiyun fcb->sectors_per_block = nand_erasesize / nand_writesize;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun fcb->num_ecc_blocks_per_page = (nand_writesize / 512) - 1;
271*4882a593Smuzhiyun fcb->ecc_block_0_size = 512;
272*4882a593Smuzhiyun fcb->ecc_block_n_size = 512;
273*4882a593Smuzhiyun fcb->metadata_bytes = 10;
274*4882a593Smuzhiyun fcb->ecc_block_n_ecc_type = mx28_nand_get_ecc_strength(
275*4882a593Smuzhiyun nand_writesize, nand_oobsize) >> 1;
276*4882a593Smuzhiyun fcb->ecc_block_0_ecc_type = mx28_nand_get_ecc_strength(
277*4882a593Smuzhiyun nand_writesize, nand_oobsize) >> 1;
278*4882a593Smuzhiyun if (fcb->ecc_block_n_ecc_type == 0) {
279*4882a593Smuzhiyun printf("MX28 NAND: Unsupported NAND geometry\n");
280*4882a593Smuzhiyun goto err;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun fcb->boot_patch = 0;
284*4882a593Smuzhiyun fcb->patch_sectors = 0;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun fcb->badblock_marker_byte = mx28_nand_mark_byte_offset();
287*4882a593Smuzhiyun fcb->badblock_marker_start_bit = mx28_nand_mark_bit_offset();
288*4882a593Smuzhiyun fcb->bb_marker_physical_offset = nand_writesize;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun stride_size_bytes = STRIDE_PAGES * nand_writesize;
291*4882a593Smuzhiyun bcb_size_bytes = stride_size_bytes * STRIDE_COUNT;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun bootstream_size_pages = (size + (nand_writesize - 1)) /
294*4882a593Smuzhiyun nand_writesize;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun fw1_start_page = 2 * bcb_size_bytes / nand_writesize;
297*4882a593Smuzhiyun fw2_start_page = (2 * bcb_size_bytes + MAX_BOOTSTREAM_SIZE) /
298*4882a593Smuzhiyun nand_writesize;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun fcb->firmware1_starting_sector = fw1_start_page;
301*4882a593Smuzhiyun fcb->firmware2_starting_sector = fw2_start_page;
302*4882a593Smuzhiyun fcb->sectors_in_firmware1 = bootstream_size_pages;
303*4882a593Smuzhiyun fcb->sectors_in_firmware2 = bootstream_size_pages;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun fcb->dbbt_search_area_start_address = STRIDE_PAGES * STRIDE_COUNT;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun return fcb;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun err:
310*4882a593Smuzhiyun free(fcb);
311*4882a593Smuzhiyun return NULL;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
mx28_nand_get_dbbt(void)314*4882a593Smuzhiyun static struct mx28_nand_dbbt *mx28_nand_get_dbbt(void)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun struct mx28_nand_dbbt *dbbt;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun dbbt = malloc(nand_writesize);
319*4882a593Smuzhiyun if (!dbbt) {
320*4882a593Smuzhiyun printf("MX28 NAND: Unable to allocate DBBT\n");
321*4882a593Smuzhiyun return NULL;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun memset(dbbt, 0, nand_writesize);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun dbbt->fingerprint = 0x54424244;
327*4882a593Smuzhiyun dbbt->version = 0x1;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun return dbbt;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
mx28_nand_parity_13_8(const uint8_t b)332*4882a593Smuzhiyun static inline uint8_t mx28_nand_parity_13_8(const uint8_t b)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun uint32_t parity = 0, tmp;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun tmp = ((b >> 6) ^ (b >> 5) ^ (b >> 3) ^ (b >> 2)) & 1;
337*4882a593Smuzhiyun parity |= tmp << 0;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun tmp = ((b >> 7) ^ (b >> 5) ^ (b >> 4) ^ (b >> 2) ^ (b >> 1)) & 1;
340*4882a593Smuzhiyun parity |= tmp << 1;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun tmp = ((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 1) ^ (b >> 0)) & 1;
343*4882a593Smuzhiyun parity |= tmp << 2;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun tmp = ((b >> 7) ^ (b >> 4) ^ (b >> 3) ^ (b >> 0)) & 1;
346*4882a593Smuzhiyun parity |= tmp << 3;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun tmp = ((b >> 6) ^ (b >> 4) ^ (b >> 3) ^
349*4882a593Smuzhiyun (b >> 2) ^ (b >> 1) ^ (b >> 0)) & 1;
350*4882a593Smuzhiyun parity |= tmp << 4;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun return parity;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
mx28_nand_fcb_block(struct mx28_nand_fcb * fcb)355*4882a593Smuzhiyun static uint8_t *mx28_nand_fcb_block(struct mx28_nand_fcb *fcb)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun uint8_t *block;
358*4882a593Smuzhiyun uint8_t *ecc;
359*4882a593Smuzhiyun int i;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun block = malloc(nand_writesize + nand_oobsize);
362*4882a593Smuzhiyun if (!block) {
363*4882a593Smuzhiyun printf("MX28 NAND: Unable to allocate FCB block\n");
364*4882a593Smuzhiyun return NULL;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun memset(block, 0, nand_writesize + nand_oobsize);
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun /* Update the FCB checksum */
370*4882a593Smuzhiyun fcb->checksum = mx28_nand_block_csum(((uint8_t *)fcb) + 4, 508);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun /* Figure 12-11. in iMX28RM, rev. 1, says FCB is at offset 12 */
373*4882a593Smuzhiyun memcpy(block + 12, fcb, sizeof(struct mx28_nand_fcb));
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun /* ECC is at offset 12 + 512 */
376*4882a593Smuzhiyun ecc = block + 12 + 512;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun /* Compute the ECC parity */
379*4882a593Smuzhiyun for (i = 0; i < sizeof(struct mx28_nand_fcb); i++)
380*4882a593Smuzhiyun ecc[i] = mx28_nand_parity_13_8(block[i + 12]);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun return block;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
mx28_nand_write_fcb(struct mx28_nand_fcb * fcb,uint8_t * buf)385*4882a593Smuzhiyun static int mx28_nand_write_fcb(struct mx28_nand_fcb *fcb, uint8_t *buf)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun uint32_t offset;
388*4882a593Smuzhiyun uint8_t *fcbblock;
389*4882a593Smuzhiyun int ret = 0;
390*4882a593Smuzhiyun int i;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun fcbblock = mx28_nand_fcb_block(fcb);
393*4882a593Smuzhiyun if (!fcbblock)
394*4882a593Smuzhiyun return -1;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun for (i = 0; i < STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
397*4882a593Smuzhiyun offset = i * nand_writesize;
398*4882a593Smuzhiyun memcpy(buf + offset, fcbblock, nand_writesize + nand_oobsize);
399*4882a593Smuzhiyun /* Mark the NAND page is OK. */
400*4882a593Smuzhiyun buf[offset + nand_writesize] = 0xff;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun free(fcbblock);
404*4882a593Smuzhiyun return ret;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
mx28_nand_write_dbbt(struct mx28_nand_dbbt * dbbt,uint8_t * buf)407*4882a593Smuzhiyun static int mx28_nand_write_dbbt(struct mx28_nand_dbbt *dbbt, uint8_t *buf)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun uint32_t offset;
410*4882a593Smuzhiyun int i = STRIDE_PAGES * STRIDE_COUNT;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun for (; i < 2 * STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
413*4882a593Smuzhiyun offset = i * nand_writesize;
414*4882a593Smuzhiyun memcpy(buf + offset, dbbt, sizeof(struct mx28_nand_dbbt));
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun return 0;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
mx28_nand_write_firmware(struct mx28_nand_fcb * fcb,int infd,uint8_t * buf)420*4882a593Smuzhiyun static int mx28_nand_write_firmware(struct mx28_nand_fcb *fcb, int infd,
421*4882a593Smuzhiyun uint8_t *buf)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun int ret;
424*4882a593Smuzhiyun off_t size;
425*4882a593Smuzhiyun uint32_t offset1, offset2;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun size = lseek(infd, 0, SEEK_END);
428*4882a593Smuzhiyun lseek(infd, 0, SEEK_SET);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun offset1 = fcb->firmware1_starting_sector * nand_writesize;
431*4882a593Smuzhiyun offset2 = fcb->firmware2_starting_sector * nand_writesize;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun ret = read(infd, buf + offset1, size);
434*4882a593Smuzhiyun if (ret != size)
435*4882a593Smuzhiyun return -1;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun memcpy(buf + offset2, buf + offset1, size);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun return 0;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
usage(void)442*4882a593Smuzhiyun static void usage(void)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun printf(
445*4882a593Smuzhiyun "Usage: mxsboot [ops] <type> <infile> <outfile>\n"
446*4882a593Smuzhiyun "Augment BootStream file with a proper header for i.MX28 boot\n"
447*4882a593Smuzhiyun "\n"
448*4882a593Smuzhiyun " <type> type of image:\n"
449*4882a593Smuzhiyun " \"nand\" for NAND image\n"
450*4882a593Smuzhiyun " \"sd\" for SD image\n"
451*4882a593Smuzhiyun " <infile> input file, the u-boot.sb bootstream\n"
452*4882a593Smuzhiyun " <outfile> output file, the bootable image\n"
453*4882a593Smuzhiyun "\n");
454*4882a593Smuzhiyun printf(
455*4882a593Smuzhiyun "For NAND boot, these options are accepted:\n"
456*4882a593Smuzhiyun " -w <size> NAND page size\n"
457*4882a593Smuzhiyun " -o <size> NAND OOB size\n"
458*4882a593Smuzhiyun " -e <size> NAND erase size\n"
459*4882a593Smuzhiyun "\n"
460*4882a593Smuzhiyun "For SD boot, these options are accepted:\n"
461*4882a593Smuzhiyun " -p <sector> Sector where the SGTL partition starts\n"
462*4882a593Smuzhiyun );
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
mx28_create_nand_image(int infd,int outfd)465*4882a593Smuzhiyun static int mx28_create_nand_image(int infd, int outfd)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun struct mx28_nand_fcb *fcb;
468*4882a593Smuzhiyun struct mx28_nand_dbbt *dbbt;
469*4882a593Smuzhiyun int ret = -1;
470*4882a593Smuzhiyun uint8_t *buf;
471*4882a593Smuzhiyun int size;
472*4882a593Smuzhiyun ssize_t wr_size;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun size = nand_writesize * 512 + 2 * MAX_BOOTSTREAM_SIZE;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun buf = malloc(size);
477*4882a593Smuzhiyun if (!buf) {
478*4882a593Smuzhiyun printf("Can not allocate output buffer of %d bytes\n", size);
479*4882a593Smuzhiyun goto err0;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun memset(buf, 0, size);
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun fcb = mx28_nand_get_fcb(MAX_BOOTSTREAM_SIZE);
485*4882a593Smuzhiyun if (!fcb) {
486*4882a593Smuzhiyun printf("Unable to compile FCB\n");
487*4882a593Smuzhiyun goto err1;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun dbbt = mx28_nand_get_dbbt();
491*4882a593Smuzhiyun if (!dbbt) {
492*4882a593Smuzhiyun printf("Unable to compile DBBT\n");
493*4882a593Smuzhiyun goto err2;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun ret = mx28_nand_write_fcb(fcb, buf);
497*4882a593Smuzhiyun if (ret) {
498*4882a593Smuzhiyun printf("Unable to write FCB to buffer\n");
499*4882a593Smuzhiyun goto err3;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun ret = mx28_nand_write_dbbt(dbbt, buf);
503*4882a593Smuzhiyun if (ret) {
504*4882a593Smuzhiyun printf("Unable to write DBBT to buffer\n");
505*4882a593Smuzhiyun goto err3;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun ret = mx28_nand_write_firmware(fcb, infd, buf);
509*4882a593Smuzhiyun if (ret) {
510*4882a593Smuzhiyun printf("Unable to write firmware to buffer\n");
511*4882a593Smuzhiyun goto err3;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun wr_size = write(outfd, buf, size);
515*4882a593Smuzhiyun if (wr_size != size) {
516*4882a593Smuzhiyun ret = -1;
517*4882a593Smuzhiyun goto err3;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun ret = 0;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun err3:
523*4882a593Smuzhiyun free(dbbt);
524*4882a593Smuzhiyun err2:
525*4882a593Smuzhiyun free(fcb);
526*4882a593Smuzhiyun err1:
527*4882a593Smuzhiyun free(buf);
528*4882a593Smuzhiyun err0:
529*4882a593Smuzhiyun return ret;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
mx28_create_sd_image(int infd,int outfd)532*4882a593Smuzhiyun static int mx28_create_sd_image(int infd, int outfd)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun int ret = -1;
535*4882a593Smuzhiyun uint32_t *buf;
536*4882a593Smuzhiyun int size;
537*4882a593Smuzhiyun off_t fsize;
538*4882a593Smuzhiyun ssize_t wr_size;
539*4882a593Smuzhiyun struct mx28_sd_config_block *cb;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun fsize = lseek(infd, 0, SEEK_END);
542*4882a593Smuzhiyun lseek(infd, 0, SEEK_SET);
543*4882a593Smuzhiyun size = fsize + 4 * 512;
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun buf = malloc(size);
546*4882a593Smuzhiyun if (!buf) {
547*4882a593Smuzhiyun printf("Can not allocate output buffer of %d bytes\n", size);
548*4882a593Smuzhiyun goto err0;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun ret = read(infd, (uint8_t *)buf + 4 * 512, fsize);
552*4882a593Smuzhiyun if (ret != fsize) {
553*4882a593Smuzhiyun ret = -1;
554*4882a593Smuzhiyun goto err1;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun cb = (struct mx28_sd_config_block *)buf;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun cb->signature = cpu_to_le32(0x00112233);
560*4882a593Smuzhiyun cb->primary_boot_tag = cpu_to_le32(0x1);
561*4882a593Smuzhiyun cb->secondary_boot_tag = cpu_to_le32(0x1);
562*4882a593Smuzhiyun cb->num_copies = cpu_to_le32(1);
563*4882a593Smuzhiyun cb->drv_info[0].chip_num = cpu_to_le32(0x0);
564*4882a593Smuzhiyun cb->drv_info[0].drive_type = cpu_to_le32(0x0);
565*4882a593Smuzhiyun cb->drv_info[0].tag = cpu_to_le32(0x1);
566*4882a593Smuzhiyun cb->drv_info[0].first_sector_number = cpu_to_le32(sd_sector + 4);
567*4882a593Smuzhiyun cb->drv_info[0].sector_count = cpu_to_le32((size - 4) / 512);
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun wr_size = write(outfd, buf, size);
570*4882a593Smuzhiyun if (wr_size != size) {
571*4882a593Smuzhiyun ret = -1;
572*4882a593Smuzhiyun goto err1;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun ret = 0;
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun err1:
578*4882a593Smuzhiyun free(buf);
579*4882a593Smuzhiyun err0:
580*4882a593Smuzhiyun return ret;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun
parse_ops(int argc,char ** argv)583*4882a593Smuzhiyun static int parse_ops(int argc, char **argv)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun int i;
586*4882a593Smuzhiyun int tmp;
587*4882a593Smuzhiyun char *end;
588*4882a593Smuzhiyun enum param {
589*4882a593Smuzhiyun PARAM_WRITE,
590*4882a593Smuzhiyun PARAM_OOB,
591*4882a593Smuzhiyun PARAM_ERASE,
592*4882a593Smuzhiyun PARAM_PART,
593*4882a593Smuzhiyun PARAM_SD,
594*4882a593Smuzhiyun PARAM_NAND
595*4882a593Smuzhiyun };
596*4882a593Smuzhiyun int type;
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun if (argc < 4)
599*4882a593Smuzhiyun return -1;
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun for (i = 1; i < argc; i++) {
602*4882a593Smuzhiyun if (!strncmp(argv[i], "-w", 2))
603*4882a593Smuzhiyun type = PARAM_WRITE;
604*4882a593Smuzhiyun else if (!strncmp(argv[i], "-o", 2))
605*4882a593Smuzhiyun type = PARAM_OOB;
606*4882a593Smuzhiyun else if (!strncmp(argv[i], "-e", 2))
607*4882a593Smuzhiyun type = PARAM_ERASE;
608*4882a593Smuzhiyun else if (!strncmp(argv[i], "-p", 2))
609*4882a593Smuzhiyun type = PARAM_PART;
610*4882a593Smuzhiyun else /* SD/MMC */
611*4882a593Smuzhiyun break;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun tmp = strtol(argv[++i], &end, 10);
614*4882a593Smuzhiyun if (tmp % 2)
615*4882a593Smuzhiyun return -1;
616*4882a593Smuzhiyun if (tmp <= 0)
617*4882a593Smuzhiyun return -1;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun if (type == PARAM_WRITE)
620*4882a593Smuzhiyun nand_writesize = tmp;
621*4882a593Smuzhiyun if (type == PARAM_OOB)
622*4882a593Smuzhiyun nand_oobsize = tmp;
623*4882a593Smuzhiyun if (type == PARAM_ERASE)
624*4882a593Smuzhiyun nand_erasesize = tmp;
625*4882a593Smuzhiyun if (type == PARAM_PART)
626*4882a593Smuzhiyun sd_sector = tmp;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun if (strcmp(argv[i], "sd") && strcmp(argv[i], "nand"))
630*4882a593Smuzhiyun return -1;
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun if (i + 3 != argc)
633*4882a593Smuzhiyun return -1;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun return i;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
main(int argc,char ** argv)638*4882a593Smuzhiyun int main(int argc, char **argv)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun int infd, outfd;
641*4882a593Smuzhiyun int ret = 0;
642*4882a593Smuzhiyun int offset;
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun offset = parse_ops(argc, argv);
645*4882a593Smuzhiyun if (offset < 0) {
646*4882a593Smuzhiyun usage();
647*4882a593Smuzhiyun ret = 1;
648*4882a593Smuzhiyun goto err1;
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun infd = open(argv[offset + 1], O_RDONLY);
652*4882a593Smuzhiyun if (infd < 0) {
653*4882a593Smuzhiyun printf("Input BootStream file can not be opened\n");
654*4882a593Smuzhiyun ret = 2;
655*4882a593Smuzhiyun goto err1;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun outfd = open(argv[offset + 2], O_CREAT | O_TRUNC | O_WRONLY,
659*4882a593Smuzhiyun S_IRUSR | S_IWUSR);
660*4882a593Smuzhiyun if (outfd < 0) {
661*4882a593Smuzhiyun printf("Output file can not be created\n");
662*4882a593Smuzhiyun ret = 3;
663*4882a593Smuzhiyun goto err2;
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun if (!strcmp(argv[offset], "sd"))
667*4882a593Smuzhiyun ret = mx28_create_sd_image(infd, outfd);
668*4882a593Smuzhiyun else if (!strcmp(argv[offset], "nand"))
669*4882a593Smuzhiyun ret = mx28_create_nand_image(infd, outfd);
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun close(outfd);
672*4882a593Smuzhiyun err2:
673*4882a593Smuzhiyun close(infd);
674*4882a593Smuzhiyun err1:
675*4882a593Smuzhiyun return ret;
676*4882a593Smuzhiyun }
677