diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/hwstub/tools/lua/fiiox1.lua | 145 | ||||
-rw-r--r-- | utils/hwstub/tools/lua/jz.lua | 4 | ||||
-rw-r--r-- | utils/hwstub/tools/lua/jz/gpio.lua | 82 | ||||
-rw-r--r-- | utils/hwstub/tools/lua/jz/lcd.lua | 4 | ||||
-rw-r--r-- | utils/hwstub/tools/lua/jz/nand.lua | 451 |
5 files changed, 686 insertions, 0 deletions
diff --git a/utils/hwstub/tools/lua/fiiox1.lua b/utils/hwstub/tools/lua/fiiox1.lua new file mode 100644 index 0000000000..c038f4077b --- /dev/null +++ b/utils/hwstub/tools/lua/fiiox1.lua | |||
@@ -0,0 +1,145 @@ | |||
1 | -- | ||
2 | -- Fiio X1 | ||
3 | -- | ||
4 | FIIOX1 = {} | ||
5 | |||
6 | -- 0 is PF3, 1 is PE1 | ||
7 | function FIIOX1.get_backlight_type() | ||
8 | return FIIOX1.bl_type | ||
9 | end | ||
10 | |||
11 | -- 0 is V2, 1 is V1 | ||
12 | function FIIOX1.get_hw_type() | ||
13 | return FIIOX1.hw_type | ||
14 | end | ||
15 | |||
16 | function FIIOX1.hw_detect() | ||
17 | -- PA12 is used to detect hardware version | ||
18 | JZ.gpio.pin(0, 12).std_gpio_out(1) | ||
19 | FIIOX1.hw_type = JZ.gpio.pin(0, 12).read() | ||
20 | -- PA13 is used to detect backlight type | ||
21 | JZ.gpio.pin(0, 13).std_gpio_out(1) | ||
22 | FIIOX1.bl_type = JZ.gpio.pin(0, 13).read() | ||
23 | |||
24 | if FIIOX1.hw_type == 1 then | ||
25 | print("Fiio X1: hardware version: V01") | ||
26 | else | ||
27 | print("Fiio X1: hardware version: V02") | ||
28 | end | ||
29 | print(string.format("Fiio X1: backlight type: %s", FIIOX1.bl_type)) | ||
30 | end | ||
31 | |||
32 | function FIIOX1.get_backlight_pin() | ||
33 | if FIIOX1.get_backlight_type() == 0 then | ||
34 | -- PF3 | ||
35 | return JZ.gpio.pin(5, 3) | ||
36 | else | ||
37 | -- PE1 | ||
38 | return JZ.gpio.pin(4, 1) | ||
39 | end | ||
40 | end | ||
41 | |||
42 | function FIIOX1.init_backligt() | ||
43 | -- setup as output, high level to make no change | ||
44 | FIIOX1.get_backlight_pin().std_gpio_out(1) | ||
45 | end | ||
46 | |||
47 | function FIIOX1.enable_backlight(en) | ||
48 | local pin = FIIOX1.get_backlight_pin() | ||
49 | pin.clr() | ||
50 | hwstub.mdelay(1) | ||
51 | if en then | ||
52 | pin.set() | ||
53 | end | ||
54 | end | ||
55 | |||
56 | function FIIOX1.test_backlight() | ||
57 | print("backlight test") | ||
58 | print("enable backlight") | ||
59 | FIIOX1.enable_backlight(true) | ||
60 | print("sleep for 1 sec") | ||
61 | hwstub.mdelay(1000) | ||
62 | print("disable backlight") | ||
63 | FIIOX1.enable_backlight(false) | ||
64 | print("sleep for 1 sec") | ||
65 | hwstub.mdelay(1000) | ||
66 | print("enable backlight") | ||
67 | FIIOX1.enable_backlight(true) | ||
68 | end | ||
69 | |||
70 | function FIIOX1.setup_fiio_lcd_pins() | ||
71 | -- PE4: reset pin | ||
72 | JZ.gpio.pin(4, 4).std_gpio_out(1) | ||
73 | -- PC9: unknown | ||
74 | JZ.gpio.pin(2, 9).std_gpio_out(0) | ||
75 | -- PC2: unknown | ||
76 | JZ.gpio.pin(2, 2).std_gpio_out(1) | ||
77 | -- PF0: unknown | ||
78 | JZ.gpio.pin(5, 0).std_gpio_out(1) | ||
79 | end | ||
80 | |||
81 | function FIIOX1.lcd_reset() | ||
82 | local pin = JZ.gpio.pin(4, 4) | ||
83 | pin.set() | ||
84 | hwstub.mdelay(50) | ||
85 | pin.clr() | ||
86 | hwstub.mdelay(50) | ||
87 | pin.set() | ||
88 | hwstub.mdelay(150) | ||
89 | end | ||
90 | |||
91 | function FIIOX1.init_lcd() | ||
92 | -- setup Fiio X1 specific pins | ||
93 | FIIOX1.setup_fiio_lcd_pins() | ||
94 | -- reset lcd | ||
95 | JZ.lcd_reset() | ||
96 | end | ||
97 | |||
98 | -- call with nil to get automatic name | ||
99 | function FIIOX1.dump_ipl(file) | ||
100 | FIIOX1.hw_detect() | ||
101 | if file == nil then | ||
102 | file = "fiiox1_ipl_hw_v" .. FIIOX1.hw_type .. ".bin" | ||
103 | end | ||
104 | print("Dumping IPL to " .. file .." ...") | ||
105 | JZ.nand.rom.init() | ||
106 | JZ.nand.rom.read_flags() | ||
107 | local ipl = JZ.nand.rom.read_bootloader() | ||
108 | JZ.nand.rom.write_to_file(file, ipl) | ||
109 | end | ||
110 | |||
111 | -- call with nil to get automatic name | ||
112 | function FIIOX1.dump_spl(file) | ||
113 | FIIOX1.hw_detect() | ||
114 | if file == nil then | ||
115 | file = "fiiox1_spl_hw_v" .. FIIOX1.hw_type .. ".bin" | ||
116 | end | ||
117 | print("Dumping SPL to " .. file .." ...") | ||
118 | -- hardcoded parameters are specific to the Fiio X1 | ||
119 | local nand_params = { | ||
120 | bus_width = 16, | ||
121 | row_cycle = 2, | ||
122 | col_cycle = 2, | ||
123 | page_size = 2048, | ||
124 | page_per_block = 64, | ||
125 | oob_size = 64, | ||
126 | badblock_pos = 0, | ||
127 | badblock_page = 0, | ||
128 | ecc_pos = 4, | ||
129 | ecc_size = 13, | ||
130 | ecc_level = 8, | ||
131 | addr_setup_time = 4, | ||
132 | addr_hold_time = 4, | ||
133 | write_strobe_time = 4, | ||
134 | read_strobe_time = 4, | ||
135 | recovery_time = 13, | ||
136 | } | ||
137 | local spl = JZ.nand.rom.read_spl(nand_params, 0x400, 0x200) | ||
138 | JZ.nand.rom.write_to_file(file, spl) | ||
139 | end | ||
140 | |||
141 | function FIIOX1.init() | ||
142 | FIIOX1.init_backligt() | ||
143 | FIIOX1.test_backlight() | ||
144 | FIIOX1.init_lcd() | ||
145 | end | ||
diff --git a/utils/hwstub/tools/lua/jz.lua b/utils/hwstub/tools/lua/jz.lua index ab2cb8658f..b192c51b3c 100644 --- a/utils/hwstub/tools/lua/jz.lua +++ b/utils/hwstub/tools/lua/jz.lua | |||
@@ -24,3 +24,7 @@ function JZ.init() | |||
24 | print("Looking for soc " .. desc .. ": not found. Please load a soc by hand.") | 24 | print("Looking for soc " .. desc .. ": not found. Please load a soc by hand.") |
25 | end | 25 | end |
26 | end | 26 | end |
27 | |||
28 | require "jz/gpio" | ||
29 | require "jz/lcd" | ||
30 | require "jz/nand" \ No newline at end of file | ||
diff --git a/utils/hwstub/tools/lua/jz/gpio.lua b/utils/hwstub/tools/lua/jz/gpio.lua new file mode 100644 index 0000000000..d85529f9bb --- /dev/null +++ b/utils/hwstub/tools/lua/jz/gpio.lua | |||
@@ -0,0 +1,82 @@ | |||
1 | --- | ||
2 | --- GPIO | ||
3 | --- | ||
4 | JZ.gpio = {} | ||
5 | |||
6 | |||
7 | function JZ.gpio.pinmask(bank, mask) | ||
8 | local t = {} | ||
9 | t.read = function() | ||
10 | return bit32.band(HW.GPIO.IN[bank].read(), mask) | ||
11 | end | ||
12 | |||
13 | t.write = function(val) | ||
14 | if val then t.set() else t.clr() end | ||
15 | end | ||
16 | |||
17 | t.set = function() | ||
18 | HW.GPIO.OUT[bank].SET.write(mask) | ||
19 | end | ||
20 | |||
21 | t.clr = function() | ||
22 | HW.GPIO.OUT[bank].CLR.write(mask) | ||
23 | end | ||
24 | |||
25 | t.gpio = function() | ||
26 | HW.GPIO.FUN[bank].CLR.write(mask) | ||
27 | HW.GPIO.SEL[bank].CLR.write(mask) | ||
28 | end | ||
29 | |||
30 | t.dir = function(out) | ||
31 | if out then | ||
32 | HW.GPIO.DIR[bank].SET.write(mask) | ||
33 | else | ||
34 | HW.GPIO.DIR[bank].CLR.write(mask) | ||
35 | end | ||
36 | end | ||
37 | |||
38 | t.pull = function(val) | ||
39 | if val then | ||
40 | HW.GPIO.PULL[bank].CLR.write(mask) | ||
41 | else | ||
42 | HW.GPIO.PULL[bank].SET.write(mask) | ||
43 | end | ||
44 | end | ||
45 | |||
46 | t.std_gpio_out = function(data) | ||
47 | t.gpio() | ||
48 | t.dir(true) | ||
49 | t.pull(false) | ||
50 | t.write(data) | ||
51 | end | ||
52 | |||
53 | t.gpio_in = function(data) | ||
54 | t.gpio() | ||
55 | t.dir(false) | ||
56 | end | ||
57 | |||
58 | t.std_function = function(fun_nr) | ||
59 | HW.GPIO.FUN[bank].SET.write(mask) | ||
60 | if fun_nr >= 2 then | ||
61 | HW.GPIO.TRG[bank].SET.write(mask) | ||
62 | fun_nr = fun_nr - 2 | ||
63 | else | ||
64 | HW.GPIO.TRG[bank].CLR.write(mask) | ||
65 | end | ||
66 | if fun_nr >= 2 then | ||
67 | HW.GPIO.SEL[bank].SET.write(mask) | ||
68 | else | ||
69 | HW.GPIO.SEL[bank].CLR.write(mask) | ||
70 | end | ||
71 | end | ||
72 | return t | ||
73 | end | ||
74 | |||
75 | function JZ.gpio.pin(bank,pin) | ||
76 | local mask = bit32.lshift(1, pin) | ||
77 | local t = JZ.gpio.pinmask(bank,mask) | ||
78 | t.read = function() | ||
79 | return bit32.extract(HW.GPIO.IN[bank].read(), pin) | ||
80 | end | ||
81 | return t | ||
82 | end \ No newline at end of file | ||
diff --git a/utils/hwstub/tools/lua/jz/lcd.lua b/utils/hwstub/tools/lua/jz/lcd.lua new file mode 100644 index 0000000000..2e626e903f --- /dev/null +++ b/utils/hwstub/tools/lua/jz/lcd.lua | |||
@@ -0,0 +1,4 @@ | |||
1 | --- | ||
2 | --- GPIO | ||
3 | --- | ||
4 | JZ.lcd = {} | ||
diff --git a/utils/hwstub/tools/lua/jz/nand.lua b/utils/hwstub/tools/lua/jz/nand.lua new file mode 100644 index 0000000000..2db8ab050b --- /dev/null +++ b/utils/hwstub/tools/lua/jz/nand.lua | |||
@@ -0,0 +1,451 @@ | |||
1 | --- | ||
2 | --- GPIO | ||
3 | --- | ||
4 | JZ.nand = {} | ||
5 | JZ.nand.rom = {} | ||
6 | |||
7 | function JZ.nand.init_pins(buswidth) | ||
8 | -- PA[21,19,18]: cs1, fre, fwe | ||
9 | JZ.gpio.pinmask(0, 0x2c0000).std_function(0) | ||
10 | JZ.gpio.pinmask(0, 0x2c0000).pull(false) | ||
11 | if buswidth == 16 then | ||
12 | -- PA[15:0]: d{15-0} | ||
13 | JZ.gpio.pinmask(0, 0xffff).std_function(0) | ||
14 | else | ||
15 | -- PA[7:0]: d{7-0} | ||
16 | JZ.gpio.pinmask(0, 0xff).std_function(0) | ||
17 | end | ||
18 | -- PB[1:0]: ale, cle | ||
19 | JZ.gpio.pinmask(1, 3).std_function(0) | ||
20 | JZ.gpio.pinmask(1, 3).pull(false) | ||
21 | -- PA20: rb# | ||
22 | JZ.gpio.pin(0, 20).gpio_in() | ||
23 | end | ||
24 | |||
25 | function JZ.nand.send_cmd(cmd) | ||
26 | DEV.write8(0xba400000, cmd) | ||
27 | end | ||
28 | |||
29 | function JZ.nand.send_addr(addr) | ||
30 | DEV.write8(0xba800000, addr) | ||
31 | end | ||
32 | |||
33 | function JZ.nand.read_data8() | ||
34 | return DEV.read8(0xba000000) | ||
35 | end | ||
36 | |||
37 | function JZ.nand.read_data32() | ||
38 | -- Boot ROM cannot do 16-bit read/write (those end up being 2x8-bit) | ||
39 | return DEV.read32(0xba000000) | ||
40 | end | ||
41 | |||
42 | function JZ.nand.wait_ready() | ||
43 | local pin = JZ.gpio.pin(0, 20) | ||
44 | -- wait ready | ||
45 | while pin.read() == 0 do end | ||
46 | end | ||
47 | |||
48 | function JZ.nand.set_buswidth(buswidth) | ||
49 | if buswidth == 8 then | ||
50 | HW.NEMC.SMC[1].BW.write("8BIT") | ||
51 | elseif buswidth == 16 then | ||
52 | HW.NEMC.SMC[1].BW.write("16BIT") | ||
53 | else | ||
54 | error("invalid buswidth") | ||
55 | end | ||
56 | end | ||
57 | -- {row,col}cycle must be 2 or 3 | ||
58 | -- buswidth must be 8 or 16 | ||
59 | -- count is the number of bytes to read (must be multiple of 2 is buswidth is 16) | ||
60 | -- function returns a table of bytes | ||
61 | function JZ.nand.read_page(col,colcycle,row,rowcycle,buswidth,count) | ||
62 | JZ.nand.set_buswidth(buswidth) | ||
63 | -- read page first cycle | ||
64 | JZ.nand.send_cmd(0) | ||
65 | -- column | ||
66 | JZ.nand.send_addr(col) | ||
67 | JZ.nand.send_addr(bit32.rshift(col, 8)) | ||
68 | if colcycle == 3 then | ||
69 | JZ.nand.send_addr(bit32.rshift(col, 16)) | ||
70 | end | ||
71 | -- row | ||
72 | JZ.nand.send_addr(row) | ||
73 | JZ.nand.send_addr(bit32.rshift(row, 8)) | ||
74 | if rowcycle == 3 then | ||
75 | JZ.nand.send_addr(bit32.rshift(row, 16)) | ||
76 | end | ||
77 | -- read page second cycle | ||
78 | JZ.nand.send_cmd(0x30) | ||
79 | -- wait ready | ||
80 | JZ.nand.wait_ready() | ||
81 | -- read | ||
82 | return JZ.nand.read_page_data(buswidth,count) | ||
83 | end | ||
84 | |||
85 | function JZ.nand.read_page2(params,col,row,count) | ||
86 | return JZ.nand.read_page(col,params.col_cycle,row,params.row_cycle,params.bus_width,count) | ||
87 | end | ||
88 | |||
89 | -- read data, assuming read page command was sent | ||
90 | function JZ.nand.read_page_data(buswidth,count) | ||
91 | -- read | ||
92 | data = {} | ||
93 | if buswidth == 8 then | ||
94 | for i=0, count-1 do | ||
95 | data[i] = JZ.nand.read_data8() | ||
96 | end | ||
97 | else | ||
98 | for i=0, count-1, 4 do | ||
99 | local hw = JZ.nand.read_data32() | ||
100 | data[i] = bit32.band(hw, 0xff) | ||
101 | data[i + 1] = bit32.band(bit32.rshift(hw, 8), 0xff) | ||
102 | data[i + 2] = bit32.band(bit32.rshift(hw, 16), 0xff) | ||
103 | data[i + 3] = bit32.band(bit32.rshift(hw, 24), 0xff) | ||
104 | end | ||
105 | end | ||
106 | return data | ||
107 | end | ||
108 | |||
109 | function JZ.nand.read_oob(params,page) | ||
110 | --[[ | ||
111 | NAND flash are magic, every setup is different, so basically: | ||
112 | - if the page size is 512, that's a special case and we need to use a special | ||
113 | command to read OOB, also note that 512-byte NAND only have one cycle column address | ||
114 | - otherwise, assume OOB is after the data (so at offset page_size in bytes), | ||
115 | but beware that for 16-bit bus, column address is in words, not bytes | ||
116 | For simplicity, we do not support 512-byte NAND at the moment | ||
117 | ]] | ||
118 | -- compute column address of OOB data | ||
119 | local col_addr = params.page_size | ||
120 | if params.bus_width == 16 then | ||
121 | col_addr = params.page_size / 2 | ||
122 | end | ||
123 | -- read page | ||
124 | return JZ.nand.read_page2(params,col_addr,page,params.oob_size) | ||
125 | end | ||
126 | |||
127 | --[[ | ||
128 | setup NAND parameters, the table should contain: | ||
129 | - bus_width: 8 or 16, | ||
130 | - addr_setup_time: in cycles | ||
131 | - addr_hold_time: in cycles | ||
132 | - write_strobe_time: in cycles | ||
133 | - read_strobe_time: in cycles | ||
134 | - recovery_time: in cycles | ||
135 | ]] | ||
136 | function JZ.nand.setup(params) | ||
137 | JZ.nand.init_pins(params.bus_width) | ||
138 | HW.NEMC.SMC[1].BL.write(params.bus_width == 8 and "8" or "16") | ||
139 | HW.NEMC.SMC[1].TAS.write(params.addr_setup_time) | ||
140 | HW.NEMC.SMC[1].TAH.write(params.addr_hold_time) | ||
141 | HW.NEMC.SMC[1].TBP.write(params.write_strobe_time) | ||
142 | HW.NEMC.SMC[1].TAW.write(params.read_strobe_time) | ||
143 | HW.NEMC.SMC[1].STRV.write(params.recovery_time) | ||
144 | end | ||
145 | |||
146 | function JZ.nand.reset() | ||
147 | print("NAND: reset") | ||
148 | JZ.nand.send_cmd(0xff) | ||
149 | JZ.nand.wait_ready() | ||
150 | end | ||
151 | |||
152 | -- init nand like ROM | ||
153 | function JZ.nand.rom.init() | ||
154 | -- init pins to 16-bit in doubt | ||
155 | JZ.nand.init_pins(16) | ||
156 | -- take safest setting: 8-bit, max TAS, max TAH, max read/write strobe wait | ||
157 | HW.NEMC.SMC[1].write(0xfff7700) | ||
158 | -- enable flash on CS1 with CS# always asserted | ||
159 | HW.NEMC.NFC.write(3) | ||
160 | -- reset | ||
161 | JZ.nand.reset() | ||
162 | end | ||
163 | |||
164 | function JZ.nand.rom.parse_flag(data, offset) | ||
165 | local cnt_55 = 0 | ||
166 | local cnt_aa = 0 | ||
167 | for i = offset,offset + 31 do | ||
168 | if data[i] == 0x55 then | ||
169 | cnt_55 = cnt_55 + 1 | ||
170 | elseif data[i] == 0xaa then | ||
171 | cnt_aa = cnt_aa + 1 | ||
172 | end | ||
173 | end | ||
174 | if cnt_55 >= 7 then | ||
175 | return 0x55 | ||
176 | elseif cnt_aa >= 7 then | ||
177 | return 0xaa | ||
178 | else | ||
179 | return 0xff | ||
180 | end | ||
181 | end | ||
182 | |||
183 | function JZ.nand.rom.read_page(col,row,count) | ||
184 | return JZ.nand.read_page(col, JZ.nand.rom.colcycle, row, JZ.nand.rom.rowcycle, | ||
185 | JZ.nand.rom.buswidth, count) | ||
186 | end | ||
187 | |||
188 | function JZ.nand.rom.read_page_data(count) | ||
189 | return JZ.nand.read_page_data(JZ.nand.rom.buswidth, count) | ||
190 | end | ||
191 | |||
192 | -- read flash parameters | ||
193 | function JZ.nand.rom.read_flags() | ||
194 | local flags = nil | ||
195 | -- read first page | ||
196 | for colcycle = 2,3 do | ||
197 | flags = JZ.nand.read_page(0,colcycle,0,3,8,160) | ||
198 | local buswidth_flag = JZ.nand.rom.parse_flag(flags, 0) | ||
199 | if buswidth_flag == 0x55 then | ||
200 | -- set to 8-bit | ||
201 | JZ.nand.rom.colcycle = colcycle | ||
202 | JZ.nand.rom.buswidth = 8 | ||
203 | break | ||
204 | elseif buswidth_flag == 0xaa then | ||
205 | -- set to 16-bit | ||
206 | JZ.nand.rom.colcycle = colcycle | ||
207 | JZ.nand.rom.buswidth = 16 | ||
208 | break | ||
209 | end | ||
210 | end | ||
211 | if JZ.nand.rom.buswidth == nil then | ||
212 | error("Cannot read flags") | ||
213 | end | ||
214 | print("NAND: colcycle = " .. JZ.nand.rom.colcycle) | ||
215 | print("NAND: buswidth = " .. JZ.nand.rom.buswidth) | ||
216 | -- reread flags correctly now | ||
217 | flags = JZ.nand.read_page(0,JZ.nand.rom.colcycle,0,3,JZ.nand.rom.buswidth,160) | ||
218 | -- rowcycle | ||
219 | local rowcycle_flag = JZ.nand.rom.parse_flag(flags, 64) | ||
220 | if rowcycle_flag == 0x55 then | ||
221 | JZ.nand.rom.rowcycle = 2 | ||
222 | elseif rowcycle_flag == 0xaa then | ||
223 | JZ.nand.rom.rowcycle = 3 | ||
224 | else | ||
225 | error("invalid rowcycle flag") | ||
226 | end | ||
227 | print("NAND: rowcycle = " .. JZ.nand.rom.rowcycle) | ||
228 | -- pagesize | ||
229 | local pagesize1_flag = JZ.nand.rom.parse_flag(flags, 96) | ||
230 | local pagesize0_flag = JZ.nand.rom.parse_flag(flags, 128) | ||
231 | if pagesize1_flag == 0x55 and pagesize0_flag == 0x55 then | ||
232 | JZ.nand.rom.pagesize = 512 | ||
233 | elseif pagesize1_flag == 0x55 and pagesize0_flag == 0xaa then | ||
234 | JZ.nand.rom.pagesize = 2048 | ||
235 | elseif pagesize1_flag == 0xaa and pagesize0_flag == 0x55 then | ||
236 | JZ.nand.rom.pagesize = 4096 | ||
237 | elseif pagesize1_flag == 0xaa and pagesize0_flag == 0xaa then | ||
238 | JZ.nand.rom.pagesize = 8192 | ||
239 | else | ||
240 | error(string.format("invalid pagesize flag: %#x,%#x", pagesize1_flag, pagesize0_flag)) | ||
241 | end | ||
242 | print("NAND: pagesize = " .. JZ.nand.rom.pagesize) | ||
243 | end | ||
244 | |||
245 | -- read bootloader | ||
246 | function JZ.nand.rom.read_bootloader() | ||
247 | -- computer number of blocks per page | ||
248 | local bl_size = 256 | ||
249 | local bl_per_page = JZ.nand.rom.pagesize / bl_size | ||
250 | local ecc_per_bl = 39 | ||
251 | local bootloader_size = 8 * 1024 | ||
252 | local bootloader = {} | ||
253 | |||
254 | local page_offset = 0 | ||
255 | while true do | ||
256 | local all_ok = true | ||
257 | print("NAND: try at page offset " .. page_offset) | ||
258 | for page = 0, bootloader_size / JZ.nand.rom.pagesize - 1 do | ||
259 | print("NAND: page " .. page) | ||
260 | -- enable randomizer | ||
261 | HW.NEMC.PNC.write(3) | ||
262 | -- read ECC | ||
263 | local ecc = JZ.nand.rom.read_page(0, page_offset + 2 * page + 1, ecc_per_bl * bl_per_page) | ||
264 | -- disable randomizer | ||
265 | HW.NEMC.PNC.write(0) | ||
266 | HW.NEMC.NFC.write(0) | ||
267 | HW.NEMC.NFC.write(3) | ||
268 | -- send read page commannd, but don't read the data just yet | ||
269 | JZ.nand.rom.read_page(0, page_offset + 2 * page, 0) | ||
270 | -- for each block | ||
271 | for bl = 0, bl_per_page - 1 do | ||
272 | print("NAND: block " .. bl) | ||
273 | -- enable randomizer (except for first block of first page) | ||
274 | if page ~=0 or bl ~= 0 then | ||
275 | HW.NEMC.PNC.write(3) | ||
276 | end | ||
277 | -- read data | ||
278 | local data = JZ.nand.rom.read_page_data(bl_size) | ||
279 | -- disable randomizer | ||
280 | HW.NEMC.PNC.write(0) | ||
281 | -- setup bch | ||
282 | HW.BCH.INTS.write(0xffffffff) | ||
283 | HW.BCH.CTRL.SET.write(0x2b) | ||
284 | HW.BCH.CTRL.CLR.write(0x4) | ||
285 | HW.BCH.COUNT.DEC.write((bl_size + ecc_per_bl) * 2) | ||
286 | for i = 0, bl_size - 1 do | ||
287 | HW.BCH.DATA.write(data[i]) | ||
288 | end | ||
289 | for i = 0, ecc_per_bl - 1 do | ||
290 | HW.BCH.DATA.write(ecc[bl * ecc_per_bl + i]) | ||
291 | end | ||
292 | while HW.BCH.INTS.DECF.read() == 0 do | ||
293 | end | ||
294 | HW.BCH.CTRL.CLR.write(1) | ||
295 | print(string.format("NAND: ecc = 0x%x", HW.BCH.INTS.read())) | ||
296 | -- now fix the errors | ||
297 | if HW.BCH.INTS.UNCOR.read() == 1 then | ||
298 | print("NAND: uncorrectable errors !") | ||
299 | all_ok = false | ||
300 | end | ||
301 | print(string.format("NAND: correcting %d errors", HW.BCH.INTS.ERRC.read())) | ||
302 | if HW.BCH.INTS.ERRC.read() > 0 then | ||
303 | error("Error correction is not implemented for now") | ||
304 | end | ||
305 | for i = 0, bl_size - 1 do | ||
306 | bootloader[(page * bl_per_page + bl) * bl_size + i] = data[i] | ||
307 | end | ||
308 | end | ||
309 | end | ||
310 | if all_ok then | ||
311 | break | ||
312 | end | ||
313 | page_offset = page_offset + 16 * 1024 / JZ.nand.rom.pagesize | ||
314 | end | ||
315 | return bootloader | ||
316 | end | ||
317 | |||
318 | --[[ | ||
319 | read SPL: offset and size in pages, the param table should contain: | ||
320 | - page_size: page size in bytes (exclusing spare) | ||
321 | - oob_size: spare data size in bytes | ||
322 | - page_per_block: number of pages per block | ||
323 | - ecc_pos: offset within spare of the ecc data | ||
324 | - badblock_pos: offset within spare of the badblock marker (only one page per block is marked) | ||
325 | - badblock_page: page number within block of the page containing badblock marker in spare | ||
326 | - col_cycle: number of cycles for column address | ||
327 | - row_cycle: number of cycles for row address | ||
328 | - ecc_size: ECC size in bytes | ||
329 | - ecc_level: level of error correction in bits: 4, 8, 12, ... | ||
330 | ]] | ||
331 | function JZ.nand.rom.read_spl(params, offset, size) | ||
332 | --[[ | ||
333 | On-flash format: each block contains page_per_block pages, | ||
334 | where each page contains page_size bytes, follows by oob_size spare bytes. | ||
335 | The spare area contains a bad block marker at offset badblock_pos and | ||
336 | the ECC data at offset ecc_pos. Note that only one page within each block | ||
337 | actually contains the bad block marker: this page is badblock_page. The marker | ||
338 | is 0xff is the block is valid. Any invalid block is skipped. | ||
339 | The ECC is computed on a per-512-block basis. Since a page contains several such | ||
340 | blocks, the ECC data contains consecutive ecc blocks, one for each 512-byte data | ||
341 | block. | ||
342 | |||
343 | +---------------------+ | ||
344 | |page0|page1|...|pageN| <--- block | ||
345 | +---------------------+ | ||
346 | |||
347 | +-------------------------------+ | ||
348 | |data(page_size)|spare(oob_size)| <--- page | ||
349 | +-------------------------------+ | ||
350 | |||
351 | +---------------------------------------------+ | ||
352 | |xxxx|badblock marker(1)|xxxxx|ECC data()|xxxx| <-- spare | ||
353 | +---------------------------------------------+ | ||
354 | ]] | ||
355 | local bootloader = {} | ||
356 | if (offset % params.page_per_block) ~= 0 then | ||
357 | print("Warning: SPL is not block-aligned") | ||
358 | end | ||
359 | -- setup parameters | ||
360 | JZ.nand.setup(params) | ||
361 | -- enable NAND | ||
362 | HW.NEMC.NFC.write(3) | ||
363 | -- reset | ||
364 | JZ.nand.reset() | ||
365 | -- read SPL ! | ||
366 | local checked_block = false | ||
367 | local cur_page = offset | ||
368 | local loaded_pages = 0 | ||
369 | while loaded_pages < size do | ||
370 | ::load_loop:: | ||
371 | -- if we just crossed a page boundary, reset the block check flag | ||
372 | if (cur_page % params.page_per_block) == 0 then | ||
373 | checked_block = false | ||
374 | end | ||
375 | -- check block for bad block marker if needed | ||
376 | if not checked_block then | ||
377 | print("Reading bad block marker for block " .. (cur_page / params.page_per_block) .. "...") | ||
378 | -- read OOB data | ||
379 | local oob_data = JZ.nand.read_oob(params,cur_page + params.badblock_page) | ||
380 | if oob_data[params.badblock_pos] ~= 0xff then | ||
381 | print("Bad block at " .. (cur_page / page_per_block)) | ||
382 | -- skip block | ||
383 | cur_page = ((cur_page + params.page_per_block) / params.page_per_block) * params.page_per_block | ||
384 | -- lua has no continue... | ||
385 | goto load_loop | ||
386 | end | ||
387 | checked_block = true | ||
388 | end | ||
389 | |||
390 | print("Reading page " .. cur_page .. "...") | ||
391 | -- send read page command | ||
392 | JZ.nand.read_page2(params,0,cur_page, 0) | ||
393 | local page_data = JZ.nand.read_page_data(params.bus_width,params.page_size) | ||
394 | local oob_data = JZ.nand.read_page_data(params.bus_width,params.oob_size) | ||
395 | -- handle each 512-byte block for ECC | ||
396 | local bl_size = 512 | ||
397 | for bl = 0,params.page_size/bl_size-1 do | ||
398 | print("Checking subblock " .. bl .. "...") | ||
399 | -- setup bch | ||
400 | HW.BCH.INTS.write(0xffffffff) | ||
401 | HW.BCH.CTRL.CLR.BSEL.write() -- clear level | ||
402 | HW.BCH.CTRL.SET.BSEL.write(params.ecc_level / 4 - 1) -- set level | ||
403 | HW.BCH.CTRL.SET.write(3) -- enable and reset | ||
404 | HW.BCH.CTRL.CLR.ENCE.write(0x4) -- decode | ||
405 | -- write ecc data count | ||
406 | HW.BCH.COUNT.DEC.write((bl_size + params.ecc_size) * 2) | ||
407 | -- write data | ||
408 | for j = 0, bl_size - 1 do | ||
409 | HW.BCH.DATA.write(page_data[bl_size * bl + j]) | ||
410 | end | ||
411 | -- write ecc data | ||
412 | for j = 0, params.ecc_size - 1 do | ||
413 | HW.BCH.DATA.write(oob_data[params.ecc_pos + bl * params.ecc_size + j]) | ||
414 | end | ||
415 | -- wait until bch is done | ||
416 | while HW.BCH.INTS.DECF.read() == 0 do | ||
417 | end | ||
418 | -- disable bch | ||
419 | HW.BCH.CTRL.CLR.write(1) | ||
420 | print(string.format("NAND: ecc = 0x%x", HW.BCH.INTS.read())) | ||
421 | -- now fix the errors | ||
422 | if HW.BCH.INTS.UNCOR.read() == 1 then | ||
423 | error("NAND: uncorrectable errors !") | ||
424 | end | ||
425 | print(string.format("NAND: correcting %d errors", HW.BCH.INTS.ERRC.read())) | ||
426 | if HW.BCH.INTS.ERRC.read() > 0 then | ||
427 | error("Error correction is not implemented for now") | ||
428 | end | ||
429 | for i = 0, bl_size - 1 do | ||
430 | bootloader[loaded_pages * params.page_size + bl * bl_size + i] = page_data[bl_size * bl + i] | ||
431 | end | ||
432 | end | ||
433 | cur_page = cur_page + 1 | ||
434 | loaded_pages = loaded_pages + 1 | ||
435 | end | ||
436 | -- disable NAND | ||
437 | HW.NEMC.NFC.write(0) | ||
438 | return bootloader | ||
439 | end | ||
440 | |||
441 | -- dump data | ||
442 | function JZ.nand.rom.write_to_file(file, data) | ||
443 | local f = io.open(file, "w") | ||
444 | if f == nil then error("Cannot open file or write to nil") end | ||
445 | local i = 0 | ||
446 | while type(data[i]) == "number" do | ||
447 | f:write(string.char(data[i])) | ||
448 | i = i + 1 | ||
449 | end | ||
450 | io.close(f) | ||
451 | end \ No newline at end of file | ||