summaryrefslogtreecommitdiff
path: root/utils/hwstub/tools/lua
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hwstub/tools/lua')
-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