summaryrefslogtreecommitdiffstats
path: root/utils/hwstub/tools
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2016-03-19 21:57:58 +0000
committerAmaury Pouly <amaury.pouly@gmail.com>2017-01-24 15:17:46 +0100
commit4fd9400458f131e61a18142105c2d2d3a082a057 (patch)
tree8c2802574edb52423d94a71e6caad6610dd90186 /utils/hwstub/tools
parent0b6cbd8e49eaf664cd005c6bb63a3111a4f4c308 (diff)
downloadrockbox-4fd9400458f131e61a18142105c2d2d3a082a057.tar.gz
rockbox-4fd9400458f131e61a18142105c2d2d3a082a057.zip
hwstub/tools/shell: add JZ4760B and Fiio X1 code
The jz code can do several useful things like dumping the IPL and SPL. The Fiio code can play with backlight and has code do dump the IPL and SPL with the correct parameters (extracted by reverse engineering). Change-Id: I317b3174f5db8d38c9a56670c1d45565142ec208
Diffstat (limited to 'utils/hwstub/tools')
-rw-r--r--utils/hwstub/tools/lua/fiiox1.lua145
-rw-r--r--utils/hwstub/tools/lua/jz.lua4
-rw-r--r--utils/hwstub/tools/lua/jz/gpio.lua82
-rw-r--r--utils/hwstub/tools/lua/jz/lcd.lua4
-rw-r--r--utils/hwstub/tools/lua/jz/nand.lua451
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 @@
+--
+-- Fiio X1
+--
+FIIOX1 = {}
+
+-- 0 is PF3, 1 is PE1
+function FIIOX1.get_backlight_type()
+ return FIIOX1.bl_type
+end
+
+-- 0 is V2, 1 is V1
+function FIIOX1.get_hw_type()
+ return FIIOX1.hw_type
+end
+
+function FIIOX1.hw_detect()
+ -- PA12 is used to detect hardware version
+ JZ.gpio.pin(0, 12).std_gpio_out(1)
+ FIIOX1.hw_type = JZ.gpio.pin(0, 12).read()
+ -- PA13 is used to detect backlight type
+ JZ.gpio.pin(0, 13).std_gpio_out(1)
+ FIIOX1.bl_type = JZ.gpio.pin(0, 13).read()
+
+ if FIIOX1.hw_type == 1 then
+ print("Fiio X1: hardware version: V01")
+ else
+ print("Fiio X1: hardware version: V02")
+ end
+ print(string.format("Fiio X1: backlight type: %s", FIIOX1.bl_type))
+end
+
+function FIIOX1.get_backlight_pin()
+ if FIIOX1.get_backlight_type() == 0 then
+ -- PF3
+ return JZ.gpio.pin(5, 3)
+ else
+ -- PE1
+ return JZ.gpio.pin(4, 1)
+ end
+end
+
+function FIIOX1.init_backligt()
+ -- setup as output, high level to make no change
+ FIIOX1.get_backlight_pin().std_gpio_out(1)
+end
+
+function FIIOX1.enable_backlight(en)
+ local pin = FIIOX1.get_backlight_pin()
+ pin.clr()
+ hwstub.mdelay(1)
+ if en then
+ pin.set()
+ end
+end
+
+function FIIOX1.test_backlight()
+ print("backlight test")
+ print("enable backlight")
+ FIIOX1.enable_backlight(true)
+ print("sleep for 1 sec")
+ hwstub.mdelay(1000)
+ print("disable backlight")
+ FIIOX1.enable_backlight(false)
+ print("sleep for 1 sec")
+ hwstub.mdelay(1000)
+ print("enable backlight")
+ FIIOX1.enable_backlight(true)
+end
+
+function FIIOX1.setup_fiio_lcd_pins()
+ -- PE4: reset pin
+ JZ.gpio.pin(4, 4).std_gpio_out(1)
+ -- PC9: unknown
+ JZ.gpio.pin(2, 9).std_gpio_out(0)
+ -- PC2: unknown
+ JZ.gpio.pin(2, 2).std_gpio_out(1)
+ -- PF0: unknown
+ JZ.gpio.pin(5, 0).std_gpio_out(1)
+end
+
+function FIIOX1.lcd_reset()
+ local pin = JZ.gpio.pin(4, 4)
+ pin.set()
+ hwstub.mdelay(50)
+ pin.clr()
+ hwstub.mdelay(50)
+ pin.set()
+ hwstub.mdelay(150)
+end
+
+function FIIOX1.init_lcd()
+ -- setup Fiio X1 specific pins
+ FIIOX1.setup_fiio_lcd_pins()
+ -- reset lcd
+ JZ.lcd_reset()
+end
+
+-- call with nil to get automatic name
+function FIIOX1.dump_ipl(file)
+ FIIOX1.hw_detect()
+ if file == nil then
+ file = "fiiox1_ipl_hw_v" .. FIIOX1.hw_type .. ".bin"
+ end
+ print("Dumping IPL to " .. file .." ...")
+ JZ.nand.rom.init()
+ JZ.nand.rom.read_flags()
+ local ipl = JZ.nand.rom.read_bootloader()
+ JZ.nand.rom.write_to_file(file, ipl)
+end
+
+-- call with nil to get automatic name
+function FIIOX1.dump_spl(file)
+ FIIOX1.hw_detect()
+ if file == nil then
+ file = "fiiox1_spl_hw_v" .. FIIOX1.hw_type .. ".bin"
+ end
+ print("Dumping SPL to " .. file .." ...")
+ -- hardcoded parameters are specific to the Fiio X1
+ local nand_params = {
+ bus_width = 16,
+ row_cycle = 2,
+ col_cycle = 2,
+ page_size = 2048,
+ page_per_block = 64,
+ oob_size = 64,
+ badblock_pos = 0,
+ badblock_page = 0,
+ ecc_pos = 4,
+ ecc_size = 13,
+ ecc_level = 8,
+ addr_setup_time = 4,
+ addr_hold_time = 4,
+ write_strobe_time = 4,
+ read_strobe_time = 4,
+ recovery_time = 13,
+ }
+ local spl = JZ.nand.rom.read_spl(nand_params, 0x400, 0x200)
+ JZ.nand.rom.write_to_file(file, spl)
+end
+
+function FIIOX1.init()
+ FIIOX1.init_backligt()
+ FIIOX1.test_backlight()
+ FIIOX1.init_lcd()
+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()
print("Looking for soc " .. desc .. ": not found. Please load a soc by hand.")
end
end
+
+require "jz/gpio"
+require "jz/lcd"
+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 @@
+---
+--- GPIO
+---
+JZ.gpio = {}
+
+
+function JZ.gpio.pinmask(bank, mask)
+ local t = {}
+ t.read = function()
+ return bit32.band(HW.GPIO.IN[bank].read(), mask)
+ end
+
+ t.write = function(val)
+ if val then t.set() else t.clr() end
+ end
+
+ t.set = function()
+ HW.GPIO.OUT[bank].SET.write(mask)
+ end
+
+ t.clr = function()
+ HW.GPIO.OUT[bank].CLR.write(mask)
+ end
+
+ t.gpio = function()
+ HW.GPIO.FUN[bank].CLR.write(mask)
+ HW.GPIO.SEL[bank].CLR.write(mask)
+ end
+
+ t.dir = function(out)
+ if out then
+ HW.GPIO.DIR[bank].SET.write(mask)
+ else
+ HW.GPIO.DIR[bank].CLR.write(mask)
+ end
+ end
+
+ t.pull = function(val)
+ if val then
+ HW.GPIO.PULL[bank].CLR.write(mask)
+ else
+ HW.GPIO.PULL[bank].SET.write(mask)
+ end
+ end
+
+ t.std_gpio_out = function(data)
+ t.gpio()
+ t.dir(true)
+ t.pull(false)
+ t.write(data)
+ end
+
+ t.gpio_in = function(data)
+ t.gpio()
+ t.dir(false)
+ end
+
+ t.std_function = function(fun_nr)
+ HW.GPIO.FUN[bank].SET.write(mask)
+ if fun_nr >= 2 then
+ HW.GPIO.TRG[bank].SET.write(mask)
+ fun_nr = fun_nr - 2
+ else
+ HW.GPIO.TRG[bank].CLR.write(mask)
+ end
+ if fun_nr >= 2 then
+ HW.GPIO.SEL[bank].SET.write(mask)
+ else
+ HW.GPIO.SEL[bank].CLR.write(mask)
+ end
+ end
+ return t
+end
+
+function JZ.gpio.pin(bank,pin)
+ local mask = bit32.lshift(1, pin)
+ local t = JZ.gpio.pinmask(bank,mask)
+ t.read = function()
+ return bit32.extract(HW.GPIO.IN[bank].read(), pin)
+ end
+ return t
+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 @@
+---
+--- GPIO
+---
+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 @@
+---
+--- GPIO
+---
+JZ.nand = {}
+JZ.nand.rom = {}
+
+function JZ.nand.init_pins(buswidth)
+ -- PA[21,19,18]: cs1, fre, fwe
+ JZ.gpio.pinmask(0, 0x2c0000).std_function(0)
+ JZ.gpio.pinmask(0, 0x2c0000).pull(false)
+ if buswidth == 16 then
+ -- PA[15:0]: d{15-0}
+ JZ.gpio.pinmask(0, 0xffff).std_function(0)
+ else
+ -- PA[7:0]: d{7-0}
+ JZ.gpio.pinmask(0, 0xff).std_function(0)
+ end
+ -- PB[1:0]: ale, cle
+ JZ.gpio.pinmask(1, 3).std_function(0)
+ JZ.gpio.pinmask(1, 3).pull(false)
+ -- PA20: rb#
+ JZ.gpio.pin(0, 20).gpio_in()
+end
+
+function JZ.nand.send_cmd(cmd)
+ DEV.write8(0xba400000, cmd)
+end
+
+function JZ.nand.send_addr(addr)
+ DEV.write8(0xba800000, addr)
+end
+
+function JZ.nand.read_data8()
+ return DEV.read8(0xba000000)
+end
+
+function JZ.nand.read_data32()
+ -- Boot ROM cannot do 16-bit read/write (those end up being 2x8-bit)
+ return DEV.read32(0xba000000)
+end
+
+function JZ.nand.wait_ready()
+ local pin = JZ.gpio.pin(0, 20)
+ -- wait ready
+ while pin.read() == 0 do end
+end
+
+function JZ.nand.set_buswidth(buswidth)
+ if buswidth == 8 then
+ HW.NEMC.SMC[1].BW.write("8BIT")
+ elseif buswidth == 16 then
+ HW.NEMC.SMC[1].BW.write("16BIT")
+ else
+ error("invalid buswidth")
+ end
+end
+-- {row,col}cycle must be 2 or 3
+-- buswidth must be 8 or 16
+-- count is the number of bytes to read (must be multiple of 2 is buswidth is 16)
+-- function returns a table of bytes
+function JZ.nand.read_page(col,colcycle,row,rowcycle,buswidth,count)
+ JZ.nand.set_buswidth(buswidth)
+ -- read page first cycle
+ JZ.nand.send_cmd(0)
+ -- column
+ JZ.nand.send_addr(col)
+ JZ.nand.send_addr(bit32.rshift(col, 8))
+ if colcycle == 3 then
+ JZ.nand.send_addr(bit32.rshift(col, 16))
+ end
+ -- row
+ JZ.nand.send_addr(row)
+ JZ.nand.send_addr(bit32.rshift(row, 8))
+ if rowcycle == 3 then
+ JZ.nand.send_addr(bit32.rshift(row, 16))
+ end
+ -- read page second cycle
+ JZ.nand.send_cmd(0x30)
+ -- wait ready
+ JZ.nand.wait_ready()
+ -- read
+ return JZ.nand.read_page_data(buswidth,count)
+end
+
+function JZ.nand.read_page2(params,col,row,count)
+ return JZ.nand.read_page(col,params.col_cycle,row,params.row_cycle,params.bus_width,count)
+end
+
+-- read data, assuming read page command was sent
+function JZ.nand.read_page_data(buswidth,count)
+ -- read
+ data = {}
+ if buswidth == 8 then
+ for i=0, count-1 do
+ data[i] = JZ.nand.read_data8()
+ end
+ else
+ for i=0, count-1, 4 do
+ local hw = JZ.nand.read_data32()
+ data[i] = bit32.band(hw, 0xff)
+ data[i + 1] = bit32.band(bit32.rshift(hw, 8), 0xff)
+ data[i + 2] = bit32.band(bit32.rshift(hw, 16), 0xff)
+ data[i + 3] = bit32.band(bit32.rshift(hw, 24), 0xff)
+ end
+ end
+ return data
+end
+
+function JZ.nand.read_oob(params,page)
+--[[
+NAND flash are magic, every setup is different, so basically:
+- if the page size is 512, that's a special case and we need to use a special
+ command to read OOB, also note that 512-byte NAND only have one cycle column address
+- otherwise, assume OOB is after the data (so at offset page_size in bytes),
+ but beware that for 16-bit bus, column address is in words, not bytes
+For simplicity, we do not support 512-byte NAND at the moment
+]]
+ -- compute column address of OOB data
+ local col_addr = params.page_size
+ if params.bus_width == 16 then
+ col_addr = params.page_size / 2
+ end
+ -- read page
+ return JZ.nand.read_page2(params,col_addr,page,params.oob_size)
+end
+
+--[[
+setup NAND parameters, the table should contain:
+- bus_width: 8 or 16,
+- addr_setup_time: in cycles
+- addr_hold_time: in cycles
+- write_strobe_time: in cycles
+- read_strobe_time: in cycles
+- recovery_time: in cycles
+]]
+function JZ.nand.setup(params)
+ JZ.nand.init_pins(params.bus_width)
+ HW.NEMC.SMC[1].BL.write(params.bus_width == 8 and "8" or "16")
+ HW.NEMC.SMC[1].TAS.write(params.addr_setup_time)
+ HW.NEMC.SMC[1].TAH.write(params.addr_hold_time)
+ HW.NEMC.SMC[1].TBP.write(params.write_strobe_time)
+ HW.NEMC.SMC[1].TAW.write(params.read_strobe_time)
+ HW.NEMC.SMC[1].STRV.write(params.recovery_time)
+end
+
+function JZ.nand.reset()
+ print("NAND: reset")
+ JZ.nand.send_cmd(0xff)
+ JZ.nand.wait_ready()
+end
+
+-- init nand like ROM
+function JZ.nand.rom.init()
+ -- init pins to 16-bit in doubt
+ JZ.nand.init_pins(16)
+ -- take safest setting: 8-bit, max TAS, max TAH, max read/write strobe wait
+ HW.NEMC.SMC[1].write(0xfff7700)
+ -- enable flash on CS1 with CS# always asserted
+ HW.NEMC.NFC.write(3)
+ -- reset
+ JZ.nand.reset()
+end
+
+function JZ.nand.rom.parse_flag(data, offset)
+ local cnt_55 = 0
+ local cnt_aa = 0
+ for i = offset,offset + 31 do
+ if data[i] == 0x55 then
+ cnt_55 = cnt_55 + 1
+ elseif data[i] == 0xaa then
+ cnt_aa = cnt_aa + 1
+ end
+ end
+ if cnt_55 >= 7 then
+ return 0x55
+ elseif cnt_aa >= 7 then
+ return 0xaa
+ else
+ return 0xff
+ end
+end
+
+function JZ.nand.rom.read_page(col,row,count)
+ return JZ.nand.read_page(col, JZ.nand.rom.colcycle, row, JZ.nand.rom.rowcycle,
+ JZ.nand.rom.buswidth, count)
+end
+
+function JZ.nand.rom.read_page_data(count)
+ return JZ.nand.read_page_data(JZ.nand.rom.buswidth, count)
+end
+
+-- read flash parameters
+function JZ.nand.rom.read_flags()
+ local flags = nil
+ -- read first page
+ for colcycle = 2,3 do
+ flags = JZ.nand.read_page(0,colcycle,0,3,8,160)
+ local buswidth_flag = JZ.nand.rom.parse_flag(flags, 0)
+ if buswidth_flag == 0x55 then
+ -- set to 8-bit
+ JZ.nand.rom.colcycle = colcycle
+ JZ.nand.rom.buswidth = 8
+ break
+ elseif buswidth_flag == 0xaa then
+ -- set to 16-bit
+ JZ.nand.rom.colcycle = colcycle
+ JZ.nand.rom.buswidth = 16
+ break
+ end
+ end
+ if JZ.nand.rom.buswidth == nil then
+ error("Cannot read flags")
+ end
+ print("NAND: colcycle = " .. JZ.nand.rom.colcycle)
+ print("NAND: buswidth = " .. JZ.nand.rom.buswidth)
+ -- reread flags correctly now
+ flags = JZ.nand.read_page(0,JZ.nand.rom.colcycle,0,3,JZ.nand.rom.buswidth,160)
+ -- rowcycle
+ local rowcycle_flag = JZ.nand.rom.parse_flag(flags, 64)
+ if rowcycle_flag == 0x55 then
+ JZ.nand.rom.rowcycle = 2
+ elseif rowcycle_flag == 0xaa then
+ JZ.nand.rom.rowcycle = 3
+ else
+ error("invalid rowcycle flag")
+ end
+ print("NAND: rowcycle = " .. JZ.nand.rom.rowcycle)
+ -- pagesize
+ local pagesize1_flag = JZ.nand.rom.parse_flag(flags, 96)
+ local pagesize0_flag = JZ.nand.rom.parse_flag(flags, 128)
+ if pagesize1_flag == 0x55 and pagesize0_flag == 0x55 then
+ JZ.nand.rom.pagesize = 512
+ elseif pagesize1_flag == 0x55 and pagesize0_flag == 0xaa then
+ JZ.nand.rom.pagesize = 2048
+ elseif pagesize1_flag == 0xaa and pagesize0_flag == 0x55 then
+ JZ.nand.rom.pagesize = 4096
+ elseif pagesize1_flag == 0xaa and pagesize0_flag == 0xaa then
+ JZ.nand.rom.pagesize = 8192
+ else
+ error(string.format("invalid pagesize flag: %#x,%#x", pagesize1_flag, pagesize0_flag))
+ end
+ print("NAND: pagesize = " .. JZ.nand.rom.pagesize)
+end
+
+-- read bootloader
+function JZ.nand.rom.read_bootloader()
+ -- computer number of blocks per page
+ local bl_size = 256
+ local bl_per_page = JZ.nand.rom.pagesize / bl_size
+ local ecc_per_bl = 39
+ local bootloader_size = 8 * 1024
+ local bootloader = {}
+
+ local page_offset = 0
+ while true do
+ local all_ok = true
+ print("NAND: try at page offset " .. page_offset)
+ for page = 0, bootloader_size / JZ.nand.rom.pagesize - 1 do
+ print("NAND: page " .. page)
+ -- enable randomizer
+ HW.NEMC.PNC.write(3)
+ -- read ECC
+ local ecc = JZ.nand.rom.read_page(0, page_offset + 2 * page + 1, ecc_per_bl * bl_per_page)
+ -- disable randomizer
+ HW.NEMC.PNC.write(0)
+ HW.NEMC.NFC.write(0)
+ HW.NEMC.NFC.write(3)
+ -- send read page commannd, but don't read the data just yet
+ JZ.nand.rom.read_page(0, page_offset + 2 * page, 0)
+ -- for each block
+ for bl = 0, bl_per_page - 1 do
+ print("NAND: block " .. bl)
+ -- enable randomizer (except for first block of first page)
+ if page ~=0 or bl ~= 0 then
+ HW.NEMC.PNC.write(3)
+ end
+ -- read data
+ local data = JZ.nand.rom.read_page_data(bl_size)
+ -- disable randomizer
+ HW.NEMC.PNC.write(0)
+ -- setup bch
+ HW.BCH.INTS.write(0xffffffff)
+ HW.BCH.CTRL.SET.write(0x2b)
+ HW.BCH.CTRL.CLR.write(0x4)
+ HW.BCH.COUNT.DEC.write((bl_size + ecc_per_bl) * 2)
+ for i = 0, bl_size - 1 do
+ HW.BCH.DATA.write(data[i])
+ end
+ for i = 0, ecc_per_bl - 1 do
+ HW.BCH.DATA.write(ecc[bl * ecc_per_bl + i])
+ end
+ while HW.BCH.INTS.DECF.read() == 0 do
+ end
+ HW.BCH.CTRL.CLR.write(1)
+ print(string.format("NAND: ecc = 0x%x", HW.BCH.INTS.read()))
+ -- now fix the errors
+ if HW.BCH.INTS.UNCOR.read() == 1 then
+ print("NAND: uncorrectable errors !")
+ all_ok = false
+ end
+ print(string.format("NAND: correcting %d errors", HW.BCH.INTS.ERRC.read()))
+ if HW.BCH.INTS.ERRC.read() > 0 then
+ error("Error correction is not implemented for now")
+ end
+ for i = 0, bl_size - 1 do
+ bootloader[(page * bl_per_page + bl) * bl_size + i] = data[i]
+ end
+ end
+ end
+ if all_ok then
+ break
+ end
+ page_offset = page_offset + 16 * 1024 / JZ.nand.rom.pagesize
+ end
+ return bootloader
+end
+
+--[[
+read SPL: offset and size in pages, the param table should contain:
+- page_size: page size in bytes (exclusing spare)
+- oob_size: spare data size in bytes
+- page_per_block: number of pages per block
+- ecc_pos: offset within spare of the ecc data
+- badblock_pos: offset within spare of the badblock marker (only one page per block is marked)
+- badblock_page: page number within block of the page containing badblock marker in spare
+- col_cycle: number of cycles for column address
+- row_cycle: number of cycles for row address
+- ecc_size: ECC size in bytes
+- ecc_level: level of error correction in bits: 4, 8, 12, ...
+]]
+function JZ.nand.rom.read_spl(params, offset, size)
+--[[
+On-flash format: each block contains page_per_block pages,
+where each page contains page_size bytes, follows by oob_size spare bytes.
+The spare area contains a bad block marker at offset badblock_pos and
+the ECC data at offset ecc_pos. Note that only one page within each block
+actually contains the bad block marker: this page is badblock_page. The marker
+is 0xff is the block is valid. Any invalid block is skipped.
+The ECC is computed on a per-512-block basis. Since a page contains several such
+blocks, the ECC data contains consecutive ecc blocks, one for each 512-byte data
+block.
+
++---------------------+
+|page0|page1|...|pageN| <--- block
++---------------------+
+
++-------------------------------+
+|data(page_size)|spare(oob_size)| <--- page
++-------------------------------+
+
++---------------------------------------------+
+|xxxx|badblock marker(1)|xxxxx|ECC data()|xxxx| <-- spare
++---------------------------------------------+
+]]
+ local bootloader = {}
+ if (offset % params.page_per_block) ~= 0 then
+ print("Warning: SPL is not block-aligned")
+ end
+ -- setup parameters
+ JZ.nand.setup(params)
+ -- enable NAND
+ HW.NEMC.NFC.write(3)
+ -- reset
+ JZ.nand.reset()
+ -- read SPL !
+ local checked_block = false
+ local cur_page = offset
+ local loaded_pages = 0
+ while loaded_pages < size do
+ ::load_loop::
+ -- if we just crossed a page boundary, reset the block check flag
+ if (cur_page % params.page_per_block) == 0 then
+ checked_block = false
+ end
+ -- check block for bad block marker if needed
+ if not checked_block then
+ print("Reading bad block marker for block " .. (cur_page / params.page_per_block) .. "...")
+ -- read OOB data
+ local oob_data = JZ.nand.read_oob(params,cur_page + params.badblock_page)
+ if oob_data[params.badblock_pos] ~= 0xff then
+ print("Bad block at " .. (cur_page / page_per_block))
+ -- skip block
+ cur_page = ((cur_page + params.page_per_block) / params.page_per_block) * params.page_per_block
+ -- lua has no continue...
+ goto load_loop
+ end
+ checked_block = true
+ end
+
+ print("Reading page " .. cur_page .. "...")
+ -- send read page command
+ JZ.nand.read_page2(params,0,cur_page, 0)
+ local page_data = JZ.nand.read_page_data(params.bus_width,params.page_size)
+ local oob_data = JZ.nand.read_page_data(params.bus_width,params.oob_size)
+ -- handle each 512-byte block for ECC
+ local bl_size = 512
+ for bl = 0,params.page_size/bl_size-1 do
+ print("Checking subblock " .. bl .. "...")
+ -- setup bch
+ HW.BCH.INTS.write(0xffffffff)
+ HW.BCH.CTRL.CLR.BSEL.write() -- clear level
+ HW.BCH.CTRL.SET.BSEL.write(params.ecc_level / 4 - 1) -- set level
+ HW.BCH.CTRL.SET.write(3) -- enable and reset
+ HW.BCH.CTRL.CLR.ENCE.write(0x4) -- decode
+ -- write ecc data count
+ HW.BCH.COUNT.DEC.write((bl_size + params.ecc_size) * 2)
+ -- write data
+ for j = 0, bl_size - 1 do
+ HW.BCH.DATA.write(page_data[bl_size * bl + j])
+ end
+ -- write ecc data
+ for j = 0, params.ecc_size - 1 do
+ HW.BCH.DATA.write(oob_data[params.ecc_pos + bl * params.ecc_size + j])
+ end
+ -- wait until bch is done
+ while HW.BCH.INTS.DECF.read() == 0 do
+ end
+ -- disable bch
+ HW.BCH.CTRL.CLR.write(1)
+ print(string.format("NAND: ecc = 0x%x", HW.BCH.INTS.read()))
+ -- now fix the errors
+ if HW.BCH.INTS.UNCOR.read() == 1 then
+ error("NAND: uncorrectable errors !")
+ end
+ print(string.format("NAND: correcting %d errors", HW.BCH.INTS.ERRC.read()))
+ if HW.BCH.INTS.ERRC.read() > 0 then
+ error("Error correction is not implemented for now")
+ end
+ for i = 0, bl_size - 1 do
+ bootloader[loaded_pages * params.page_size + bl * bl_size + i] = page_data[bl_size * bl + i]
+ end
+ end
+ cur_page = cur_page + 1
+ loaded_pages = loaded_pages + 1
+ end
+ -- disable NAND
+ HW.NEMC.NFC.write(0)
+ return bootloader
+end
+
+-- dump data
+function JZ.nand.rom.write_to_file(file, data)
+ local f = io.open(file, "w")
+ if f == nil then error("Cannot open file or write to nil") end
+ local i = 0
+ while type(data[i]) == "number" do
+ f:write(string.char(data[i]))
+ i = i + 1
+ end
+ io.close(f)
+end \ No newline at end of file